Commit b21f1d1da09466c10851a9cc395fdca0b00f5836

Authored by Jürgen Knödlseder
1 parent 4f190b42

Use new internal structure to store information.

include/GVOHub.hpp
... ... @@ -28,15 +28,11 @@
28 28 #define GVOHUB_HPP
29 29  
30 30 /* __ Definitions ________________________________________________________ */
31   -#define GVOHUB_NB_CLIENTS 5
32   -#define GVOHUB_NB_METHODS 128
33   -#define GVO_HUB_testing 1
34 31  
35 32 /* __ Includes ___________________________________________________________ */
36 33 #include <string>
37   -#include <list>
  34 +#include <vector>
38 35 #include <sys/socket.h>
39   -#include <semaphore.h>
40 36 #include "GBase.hpp"
41 37 #include "GXml.hpp"
42 38 #include "GXmlNode.hpp"
... ... @@ -71,82 +67,78 @@ public:
71 67  
72 68 protected:
73 69 // Protected methods
74   - void init_members(void);
75   - void copy_members(const GVOHub& client);
76   - void free_members(void);
77   - void start_hub(void);
78   - void handle_request(const socklen_t& sock);
79   - void request_ping(const socklen_t& sock);
80   - void request_register(const GXml& xml,
81   - const socklen_t& sock);
82   - void request_unregister(const GXml& xml,
  70 + void init_members(void);
  71 + void copy_members(const GVOHub& client);
  72 + void free_members(void);
  73 + void start_hub(void);
  74 + void handle_request(const socklen_t& sock);
  75 + void request_ping(const socklen_t& sock);
  76 + void request_register(const GXml& xml,
83 77 const socklen_t& sock);
84   - void request_declare_metadata(const GXml& xml,
85   - const socklen_t& sock);
86   - void request_declare_subscriptions(const GXml& xml,
87   - const socklen_t& sock);
88   - void request_set_xml_rpc_callback(const GXml& xml,
89   - const socklen_t& sock);
90   - void request_get_subscriptions(const GXml& xml,
91   - const socklen_t& sock);
92   - void request_get_registered_clients(const GXml& xml,
93   - const socklen_t& sock);
94   - void request_get_subscribed_clients(const GXml& xml,
95   - const socklen_t& sock);
96   - void request_get_metadata(const GXml& xml,
  78 + void request_unregister(const GXml& xml,
97 79 const socklen_t& sock);
98   - void request_shutdown(const socklen_t& sock);
99   - std::string get_client_key(const GXml& xml) const;
100   - int get_client_index(const GXml& xml) const;
101   - std::string get_response_value(const GXml& xml,
102   - const std::string& name) const;
103   - void get_name_value_pair(const GXmlNode* node,
104   - std::string& name,
105   - std::string& value) const;
106   - std::list<std::string> get_registrations(const GXml& xml) const;
107   - std::string get_callback_port(const GXml& xml) const;
108   - std::string get_hub_lockfile(void) const;
109   - void activate_callbacks(std::string method, char cl_id[31]);
  80 + void request_declare_metadata(const GXml& xml,
  81 + const socklen_t& sock);
  82 + void request_declare_subscriptions(const GXml& xml,
  83 + const socklen_t& sock);
  84 + void request_set_xml_rpc_callback(const GXml& xml,
  85 + const socklen_t& sock);
  86 + void request_get_subscriptions(const GXml& xml,
  87 + const socklen_t& sock);
  88 + void request_get_registered_clients(const GXml& xml,
  89 + const socklen_t& sock);
  90 + void request_get_subscribed_clients(const GXml& xml,
  91 + const socklen_t& sock);
  92 + void request_get_metadata(const GXml& xml,
  93 + const socklen_t& sock);
  94 + void request_shutdown(const socklen_t& sock);
  95 + std::string get_client_key(const GXml& xml) const;
  96 + int get_client_index(const GXml& xml) const;
  97 + std::string get_response_value(const GXml& xml,
  98 + const std::string& name) const;
  99 + void get_name_value_pair(const GXmlNode* node,
  100 + std::string& name,
  101 + std::string& value) const;
  102 + std::vector<std::string> get_subscriptions(const GXml& xml) const;
  103 + std::string get_callback_url(const GXml& xml) const;
  104 + std::string get_hub_lockfile(void) const;
  105 + void send_notifications(const std::string& method,
  106 + const std::string& client);
110 107  
111 108 // Low-level methods
112 109 void create_samp_file(void) const;
  110 + void post_samp_ok(const socklen_t& sock) const;
113 111 void post_string(const std::string& content, const socklen_t& sock) const;
114   - void post_string_callback(const std::string& content) const;
  112 + void notify(const std::string& url, const std::string& notification) const;
115 113 std::string random_string(const size_t& length) const;
116 114  
117   - // Protected structures
118   - typedef struct {
119   - char private_key[16];
120   - char name[32];
121   - char reference[32];
122   - char description[256];
123   - char icon[32];
124   - char documentation[32];
125   - char affiliation[32];
126   - char author_name[32];
127   - char email[32];
128   - char homepage[32];
129   - char port[32];
130   - char registered_methods[GVOHUB_NB_METHODS][GVOHUB_NB_METHODS]; //128 methods of 128 cars max.
131   - } connected_shm;
132   - typedef struct {
133   - int registered;
134   - sem_t lock;
135   - connected_shm metadata[GVOHUB_NB_CLIENTS];
136   - } clients;
  115 + // Protected structure
  116 + struct client {
  117 + std::string name;
  118 + std::string private_key;
  119 + std::string reference;
  120 + std::string description;
  121 + std::string icon;
  122 + std::string documentation;
  123 + std::string affiliation;
  124 + std::string author_name;
  125 + std::string email;
  126 + std::string homepage;
  127 + std::string url;
  128 + std::vector<std::string> subscriptions;
  129 + };
137 130  
138 131 // Protected members
139   - std::string m_secret; //!< Secret Hub key
140   - std::string m_hub_url; //!< The XML-RPC endpoint for communication with the hub
141   - std::string m_hub_host; //!< Hub host (extracted from XML-RPC endpoint)
142   - std::string m_hub_port; //!< Hub port (extracted from XML-RPC endpoint)
143   - std::string m_version; //!< The version of the SAMP Standard Profile implemented by the hub
144   - std::string m_hub_id; //!< Hub identifier used by the hub when it sends message itself rather than forwarding from others
145   - socklen_t m_socket; //!< Hub socket
146   - int m_cback_socket; //!< Hub socket to callback clients
147   - clients* m_clients; //!< Structure of registered clients
148   - void* m_shmem; //!< Pointer to shared memory address
149   - int m_shmem_handler; //!< Handler to shared memory
  132 + std::string m_secret; //!< Secret Hub key
  133 + std::string m_hub_url; //!< The XML-RPC endpoint for communication with the hub
  134 + std::string m_hub_host; //!< Hub host
  135 + std::string m_hub_port; //!< Hub port
  136 + std::string m_hub_path; //!< Hub path
  137 + std::string m_version; //!< The version of the SAMP Standard Profile implemented by the hub
  138 + std::string m_hub_id; //!< Hub identifier used by the hub when it sends message itself rather than forwarding from others
  139 + socklen_t m_socket; //!< Hub socket
  140 + bool m_shutdown; //!< Shutdown request
  141 + std::vector<client> m_clients; //!< Clients
150 142 };
151 143  
152 144  
... ...
src/vo/GVOClient.cpp
... ... @@ -867,9 +867,6 @@ void GVOClient::connect_to_hub(void) const
867 867 break;
868 868 }
869 869 }
870   - else {
871   - break;
872   - }
873 870  
874 871 } // endfor: looped through all results
875 872  
... ... @@ -917,7 +914,7 @@ void GVOClient::post_string(const std::string&amp; content) const
917 914 bool done = false;
918 915 do {
919 916 int length = post.length() + 1; // +1 for terminating 0
920   - int sent_length = send(m_socket, post.c_str(), length+1, 0);
  917 + int sent_length = send(m_socket, post.c_str(), length, 0);
921 918 if (sent_length < length) {
922 919 post = post.substr(sent_length, std::string::npos);
923 920 }
... ...
src/vo/GVOHub.cpp
... ... @@ -57,10 +57,9 @@
57 57 /* __ Coding definitions _________________________________________________ */
58 58 #define G_KEY 12345
59 59 //#define G_USE_FORK
60   -//#define G_USE_SHMEM
61 60  
62 61 /* __ Debug definitions __________________________________________________ */
63   -//#define G_CONSOLE_DUMP
  62 +#define G_CONSOLE_DUMP
64 63  
65 64  
66 65 /*==========================================================================
... ... @@ -217,8 +216,9 @@ std::string GVOHub::print(const GChatter&amp; chatter) const
217 216 result.append("\n"+gammalib::parformat("Hub identifier")+m_hub_id);
218 217 result.append("\n"+gammalib::parformat("Hub key")+m_secret);
219 218 result.append("\n"+gammalib::parformat("Hub URL")+m_hub_url);
220   - result.append("\n"+gammalib::parformat("Hub host (port)"));
221   - result.append(m_hub_host+" ("+m_hub_port+")");
  219 + result.append("\n"+gammalib::parformat("Hub host")+m_hub_host);
  220 + result.append("\n"+gammalib::parformat("Hub port")+m_hub_port);
  221 + result.append("\n"+gammalib::parformat("Hub path")+m_hub_path);
222 222 result.append("\n"+gammalib::parformat("SAMP protocol version"));
223 223 result.append(m_version);
224 224  
... ... @@ -243,50 +243,14 @@ void GVOHub::init_members(void)
243 243 // Initialise members
244 244 m_secret = random_string(15);
245 245 m_hub_host = "127.0.0.1";
246   - m_hub_port = "2525";
247   - m_hub_url = "http://"+m_hub_host+":"+m_hub_port+"/xmlrpc";
  246 + m_hub_port = "2526";
  247 + m_hub_path = "xmlrpc";
  248 + m_hub_url = "http://"+m_hub_host+":"+m_hub_port+"/"+m_hub_path;
248 249 m_version = "1.3";
249 250 m_hub_id = "gammalib_hub";
250 251 m_socket = -1; // Signals no socket
251   - m_cback_socket = -1; // Signals no socket
252   - m_clients = NULL;
253   - m_shmem = NULL;
254   - m_shmem_handler = 0;
255   -
256   - #if defined(G_USE_SHMEM)
257   - // Get shared memory for handling of clients
258   - if ((m_shmem_handler = shmget(G_KEY, sizeof(clients), 0666 | IPC_CREAT)) < 0) {
259   - std::string msg = "Could not open shared memory.";
260   - throw GException::invalid_value(G_INIT_MEMBERS, msg);
261   - }
262   -
263   - // Get pointer on shared memory
264   - if ((m_shmem = shmat(m_shmem_handler, NULL, 0)) == (void*) -1) {
265   - std::string msg = "Could not attach shared memory.";
266   - throw GException::invalid_value(G_INIT_MEMBERS, msg);
267   - }
268   -
269   - // Get pointer
270   - m_clients = static_cast<clients*>(m_shmem);
271   - #else
272   - m_clients = new clients;
273   - #endif
274   -
275   - // Initialise shared memory
276   - m_clients->registered = 0;
277   - for (int i = 0; i < GVOHUB_NB_CLIENTS; ++i) {
278   - strcpy(m_clients->metadata[i].reference, "NoRef");
279   - strcpy(m_clients->metadata[i].private_key, "Unknown");
280   - strcpy(m_clients->metadata[i].name, "Unknown");
281   - strcpy(m_clients->metadata[i].icon, "Unknown");
282   - strcpy(m_clients->metadata[i].documentation,"Unknown");
283   - strcpy(m_clients->metadata[i].affiliation, "Unknown");
284   - strcpy(m_clients->metadata[i].author_name, "Unknown");
285   - strcpy(m_clients->metadata[i].email, "Unknown");
286   - strcpy(m_clients->metadata[i].homepage, "Unknown");
287   - strcpy(m_clients->metadata[i].port, "Unknown");
288   - strcpy(m_clients->metadata[i].description, "Unknown");
289   - }
  252 + m_clients.clear();
  253 + m_shutdown = false;
290 254  
291 255 // Return
292 256 return;
... ... @@ -301,16 +265,16 @@ void GVOHub::init_members(void)
301 265 void GVOHub::copy_members(const GVOHub& hub)
302 266 {
303 267 // Copy members
304   - m_secret = hub.m_secret;
305   - m_hub_url = hub.m_hub_url;
306   - m_hub_host = hub.m_hub_host;
307   - m_hub_port = hub.m_hub_port;
308   - m_version = hub.m_version;
309   - m_hub_id = hub.m_hub_id;
310   - m_socket = hub.m_socket;
311   - m_cback_socket = hub.m_cback_socket;
312   -
313   - //TODO: What to do with shared memory? Copy over all data?
  268 + m_secret = hub.m_secret;
  269 + m_hub_url = hub.m_hub_url;
  270 + m_hub_host = hub.m_hub_host;
  271 + m_hub_port = hub.m_hub_port;
  272 + m_hub_path = hub.m_hub_path;
  273 + m_version = hub.m_version;
  274 + m_hub_id = hub.m_hub_id;
  275 + m_socket = hub.m_socket;
  276 + m_clients = hub.m_clients;
  277 + m_shutdown = hub.m_shutdown;
314 278  
315 279 // Return
316 280 return;
... ... @@ -327,22 +291,11 @@ void GVOHub::free_members(void)
327 291 close(m_socket);
328 292 m_socket = -1;
329 293 }
330   - if (m_cback_socket != -1) {
331   - close(m_cback_socket);
332   - m_cback_socket = -1;
333   - }
334 294  
335 295 // Remove lockfile
336 296 std::string lockurl = get_hub_lockfile();
337 297 std::remove(lockurl.c_str());
338 298  
339   - // Release shared memory
340   - #if defined(G_USE_SHMEM)
341   - struct shmid_ds *buf;
342   - shmdt(m_shmem);
343   - shmctl(m_shmem_handler, IPC_RMID, buf);
344   - #endif
345   -
346 299 // Return
347 300 return;
348 301 }
... ... @@ -358,9 +311,6 @@ void GVOHub::free_members(void)
358 311 ***************************************************************************/
359 312 void GVOHub::start_hub(void)
360 313 {
361   - // Set maximum number of clients
362   - int max_clients = 10;
363   -
364 314 // Prepare TCP/IP structure
365 315 struct sockaddr_in serv_addr;
366 316 std::memset(&serv_addr, 0, sizeof(serv_addr));
... ... @@ -368,12 +318,6 @@ void GVOHub::start_hub(void)
368 318 serv_addr.sin_addr.s_addr = inet_addr(m_hub_host.c_str());
369 319 serv_addr.sin_port = htons(gammalib::toint(m_hub_port));
370 320  
371   - // Initialise all client_socket[] to 0 so not checked
372   - socklen_t client_socket[max_clients];
373   - for (int i = 0; i < max_clients; ++i) {
374   - client_socket[i] = 0;
375   - }
376   -
377 321 // Create Hub socket
378 322 m_socket = socket(AF_INET, SOCK_STREAM, 0);
379 323  
... ... @@ -463,7 +407,7 @@ void GVOHub::start_hub(void)
463 407  
464 408 // If we have received a shutdown request then exit the event
465 409 // loop
466   - if (m_clients->registered == -1) {
  410 + if (o_clients->registered == -1) {
467 411 break;
468 412 }
469 413  
... ... @@ -477,7 +421,7 @@ void GVOHub::start_hub(void)
477 421  
478 422 // If we have received a shutdown request then exit the event
479 423 // loop
480   - if (m_clients->registered == -1) {
  424 + if (m_shutdown) {
481 425 break;
482 426 }
483 427 #endif
... ... @@ -559,16 +503,16 @@ void GVOHub::handle_request(const socklen_t&amp; sock)
559 503 request_register(xml, sock);
560 504 }
561 505 else if (method_called.compare("samp.hub.unregister") == 0) {
562   - request_unregister(xml,sock);
  506 + request_unregister(xml, sock);
563 507 }
564 508 else if (method_called.compare("samp.hub.declareMetadata") == 0) {
565   - request_declare_metadata(xml,sock);
  509 + request_declare_metadata(xml, sock);
566 510 }
567 511 else if (method_called.compare("samp.hub.declareSubscriptions") == 0) {
568   - request_declare_subscriptions(xml,sock);
  512 + request_declare_subscriptions(xml, sock);
569 513 }
570 514 else if (method_called.compare("samp.hub.setXmlrpcCallback") == 0) {
571   - request_set_xml_rpc_callback(xml,sock);
  515 + request_set_xml_rpc_callback(xml, sock);
572 516 }
573 517 else if (method_called.compare("samp.hub.getSubscriptions") == 0) {
574 518 request_get_subscriptions(xml, sock);
... ... @@ -623,21 +567,23 @@ void GVOHub::request_ping(const socklen_t&amp; sock)
623 567 std::cout << "GVOHub::request_ping" << std::endl;
624 568 #endif
625 569  
626   - // Declare message
627   - std::string msg = "";
  570 + // Declare response
  571 + std::string response = "";
628 572  
629 573 // Set response
630   - msg.append("<?xml version=\"1.0\"?>\n");
631   - msg.append("<methodResponse>\n");
632   - msg.append("<params>\n");
633   - msg.append(" <param><value/></param>\n");
634   - msg.append("</params>\n");
635   - msg.append("</methodResponse>\n");
  574 + response.append("<?xml version='1.0' encoding='UTF-8'?>\n");
  575 + response.append("<methodResponse>\n");
  576 + response.append(" <params>\n");
  577 + response.append(" <param>\n");
  578 + response.append(" <value/>\n");
  579 + response.append(" </param>\n");
  580 + response.append(" </params>\n");
  581 + response.append("</methodResponse>\n");
636 582  
637 583 // Post response
638   - post_string(msg,sock);
  584 + post_string(response, sock);
639 585  
640   - //Return
  586 + // Return
641 587 return;
642 588 }
643 589  
... ... @@ -657,58 +603,56 @@ void GVOHub::request_register(const GXml&amp; xml, const socklen_t&amp; sock)
657 603 std::cout << "GVOHub::request_register" << std::endl;
658 604 #endif
659 605  
660   - // Initialize values
661   - char cl_id[31];
662   - char selfid[124];
663   - char privatekey[124];
664   - std::string secret = random_string(15);
665   - std::string translator = m_hub_url;
  606 + // Create a new client
  607 + struct client voclient;
  608 + voclient.reference = "c"+gammalib::str(m_clients.size());
  609 + voclient.private_key = random_string(15);
666 610  
667   - // Search for a new free slot
668   - bool found = false;
669   - for (int i = 0; i < GVOHUB_NB_CLIENTS; ++i) {
670   - if (strcmp(m_clients->metadata[i].reference, "NoRef") == 0) {
671   - sprintf(cl_id, "c%d",i);
672   - strcpy(m_clients->metadata[i].reference, cl_id);
673   - sprintf(m_clients->metadata[i].private_key, "%s", secret.c_str());
674   - found = true;
675   - break;
676   - }
  611 + // Attached client
  612 + m_clients.push_back(voclient);
  613 + /*
  614 + for (int i = 0; i < m_clients.size(); ++i) {
  615 + std::cout << "Client i " << m_clients[i].reference << " key=" << m_clients[i].private_key << std::endl;
677 616 }
678   -
679   - // Throw an exception if no free slot is available
680   - if (!found) {
681   - std::string msg = "No free slot found for client.";
682   - throw GException::invalid_value(G_REGISTER_SERVICE, msg);
683   - }
684   -
685   - // Set self ID and private key
686   - sprintf(selfid, " <member><name>samp.self-id</name><value>%s</value></member>\n",cl_id);
687   - sprintf(privatekey, " <member><name>samp.private-key</name><value>%s</value></member>\n",secret.c_str());
  617 + */
688 618  
689 619 // Declare response
690 620 std::string msg = "";
691   - msg.append("<?xml version=\"1.0\" ?>\n");
  621 +
  622 + // Set response
  623 + msg.append("<?xml version='1.0' encoding='UTF-8'?>\n");
692 624 msg.append("<methodResponse>\n");
693 625 msg.append("<params>\n");
694 626 msg.append(" <param><value><struct>\n");
695   - msg.append(" <member><name>samp.hub-id</name><value>" + m_hub_id + "</value></member>\n");
696   - msg.append(selfid);
697   - msg.append(privatekey);
698   - msg.append(" <member><name>samp.status</name><value>samp.ok</value></member>\n");
699   - msg.append(" <member><name>samp.url-translator</name><value>" + translator + "</value></member>\n");
  627 + msg.append(" <member>\n");
  628 + msg.append(" <name>samp.private-key</name>\n");
  629 + msg.append(" <value>"+voclient.private_key+"</value>\n");
  630 + msg.append(" </member>\n");
  631 + msg.append(" <member>\n");
  632 + msg.append(" <name>samp.hub-id</name>\n");
  633 + msg.append(" <value>"+m_hub_id+"</value>\n");
  634 + msg.append(" </member>\n");
  635 + msg.append(" <member>\n");
  636 + msg.append(" <name>samp.self-id</name>\n");
  637 + msg.append(" <value>"+voclient.reference+"</value>\n");
  638 + msg.append(" </member>\n");
  639 + msg.append(" <member>\n");
  640 + msg.append(" <name>samp.status</name>\n");
  641 + msg.append(" <value>samp.ok</value>\n");
  642 + msg.append(" </member>\n");
  643 + msg.append(" <member>\n");
  644 + msg.append(" <name>samp.url-translator</name>\n");
  645 + msg.append(" <value>"+m_hub_url+"</value>\n");
  646 + msg.append(" </member>\n");
700 647 msg.append(" </struct></value></param>\n");
701 648 msg.append("</params>\n");
702 649 msg.append("</methodResponse>\n");
703 650  
704 651 // Post response
705   - post_string(msg,sock);
706   -
707   - // Activate callbacks
708   - activate_callbacks("samp.hub.event.register", cl_id);
  652 + post_string(msg, sock);
709 653  
710   - // Increment number of registered clients
711   - //m_clients->registered++;
  654 + // Send notifications
  655 + send_notifications("samp.hub.event.register", voclient.reference);
712 656  
713 657 //Return
714 658 return;
... ... @@ -750,22 +694,21 @@ void GVOHub::request_unregister(const GXml&amp; xml, const socklen_t&amp; sock)
750 694 // Post response
751 695 post_string(msg, sock);
752 696  
753   - // Activate callbacks
754   - activate_callbacks("samp.hub.event.unregister",
755   - m_clients->metadata[i].reference);
756   -
757   - // Reset client entry
758   - strcpy(m_clients->metadata[i].reference, "NoRef");
759   - sprintf(m_clients->metadata[i].name, "Unknown");
760   - sprintf(m_clients->metadata[i].description, "Unknown");
761   - sprintf(m_clients->metadata[i].icon, "Unknown");
762   - sprintf(m_clients->metadata[i].documentation, "Unknown");
763   - sprintf(m_clients->metadata[i].affiliation, "Unknown");
764   - sprintf(m_clients->metadata[i].email, "Unknown");
765   - sprintf(m_clients->metadata[i].author_name, "Unknown");
766   - sprintf(m_clients->metadata[i].homepage, "Unknown");
  697 + // Send notifications
  698 + send_notifications("samp.hub.event.unregister",
  699 + m_clients[i].reference);
  700 +
  701 + // Remove client
  702 + m_clients.erase(m_clients.begin()+i);
767 703  
768 704 } // endif: valid client found
  705 +
  706 + // Signal if the client was unknown
  707 + #if defined(G_CONSOLE_DUMP)
  708 + else {
  709 + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl;
  710 + }
  711 + #endif
769 712  
770 713 // Return
771 714 return;
... ... @@ -793,25 +736,15 @@ void GVOHub::request_declare_metadata(const GXml&amp; xml, const socklen_t&amp; sock)
793 736 // Continue only if index is valid
794 737 if (i != -1) {
795 738  
796   - // Get metadata
797   - std::string client_name = get_response_value(xml, "samp.name");
798   - std::string client_description = get_response_value(xml, "samp.description.text");
799   - std::string client_icon = get_response_value(xml, "samp.icon.url");
800   - std::string client_doc = get_response_value(xml, "samp.documentation.url");
801   - std::string client_affi = get_response_value(xml, "author.affiliation");
802   - std::string client_mail = get_response_value(xml, "author.email");
803   - std::string client_authname = get_response_value(xml, "author.name");
804   - std::string client_page = get_response_value(xml, "home.page");
805   -
806 739 // Store metadata
807   - sprintf(m_clients->metadata[i].name, "%s", client_name.c_str());
808   - sprintf(m_clients->metadata[i].description, "%s", client_description.c_str());
809   - sprintf(m_clients->metadata[i].icon, "%s", client_icon.c_str());
810   - sprintf(m_clients->metadata[i].documentation, "%s", client_doc.c_str());
811   - sprintf(m_clients->metadata[i].affiliation, "%s", client_affi.c_str());
812   - sprintf(m_clients->metadata[i].email, "%s", client_mail.c_str());
813   - sprintf(m_clients->metadata[i].author_name, "%s", client_authname.c_str());
814   - sprintf(m_clients->metadata[i].homepage, "%s", client_page.c_str());
  740 + m_clients[i].name = get_response_value(xml, "samp.name");;
  741 + m_clients[i].description = get_response_value(xml, "samp.description.text");
  742 + m_clients[i].icon = get_response_value(xml, "samp.icon.url");
  743 + m_clients[i].documentation = get_response_value(xml, "samp.documentation.url");
  744 + m_clients[i].affiliation = get_response_value(xml, "author.affiliation");
  745 + m_clients[i].email = get_response_value(xml, "author.email");
  746 + m_clients[i].author_name = get_response_value(xml, "author.name");
  747 + m_clients[i].homepage = get_response_value(xml, "home.page");
815 748  
816 749 // Declare message
817 750 std::string msg = "";
... ... @@ -826,8 +759,8 @@ void GVOHub::request_declare_metadata(const GXml&amp; xml, const socklen_t&amp; sock)
826 759 // Post response
827 760 post_string(msg,sock);
828 761  
829   - // Activate callbacks
830   - activate_callbacks("samp.hub.event.metadata", m_clients->metadata[i].reference);
  762 + // Send notifications
  763 + send_notifications("samp.hub.event.metadata", m_clients[i].reference);
831 764  
832 765 } // endif: client found
833 766  
... ... @@ -864,32 +797,25 @@ void GVOHub::request_declare_subscriptions(const GXml&amp; xml,const socklen_t&amp; sock
864 797 // Continue only if index is valid
865 798 if (i != -1) {
866 799  
867   - // Do stuff
868   - int j;
869   - std::list<std::string>::iterator p;
870   - std::ofstream myfile;
871   - std::string tempo;
872   - std::list<std::string> client_subscriptions = get_registrations(xml);
873   - for (j = 0, p=client_subscriptions.begin(); j<client_subscriptions.size()-1; j++,p++ ) {
874   - tempo = *p;
875   - sprintf(m_clients->metadata[i].registered_methods[j], "%s", tempo.c_str());
876   - }
  800 + // Get subscriptions
  801 + std::vector<std::string> subscriptions = get_subscriptions(xml);
877 802  
878   - // Declare response
879   - std::string msg = "";
880   - msg.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
881   - msg.append("<methodResponse>\n");
882   - msg.append("<params>\n");
883   - msg.append(" <param><value><struct>\n");
884   - msg.append(" <member><name>samp.status</name><value>samp.ok</value></member>\n");
885   - msg.append(" </struct></value></param>\n");
886   - msg.append("</params>\n");
887   - msg.append("</methodResponse>\n");
  803 + // Store subscriptions
  804 + for (int k = 0; k < subscriptions.size(); ++k) {
  805 + m_clients[i].subscriptions.push_back(subscriptions[k]);
  806 + }
888 807  
889   - // Post string
890   - post_string(msg,sock);
  808 + // Post SAMP ok
  809 + post_samp_ok(sock);
891 810  
892 811 } // endif: valid client found
  812 +
  813 + // Signal if the client was unknown
  814 + #if defined(G_CONSOLE_DUMP)
  815 + else {
  816 + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl;
  817 + }
  818 + #endif
893 819  
894 820 //Return
895 821 return;
... ... @@ -904,11 +830,12 @@ void GVOHub::request_declare_subscriptions(const GXml&amp; xml,const socklen_t&amp; sock
904 830 *
905 831 * Handles all incoming XML-RPC callback setting requests.
906 832 ***************************************************************************/
907   -void GVOHub::request_set_xml_rpc_callback(const GXml& xml,const socklen_t& sock)
  833 +void GVOHub::request_set_xml_rpc_callback(const GXml& xml,
  834 + const socklen_t& sock)
908 835 {
909 836 // Header
910 837 #if defined(G_CONSOLE_DUMP)
911   - std::cout << "GVOHub::request_declare_subscriptions" << std::endl;
  838 + std::cout << "GVOHub::request_set_xml_rpc_callback" << std::endl;
912 839 #endif
913 840  
914 841 // Get client index
... ... @@ -917,31 +844,24 @@ void GVOHub::request_set_xml_rpc_callback(const GXml&amp; xml,const socklen_t&amp; sock)
917 844 // Continue only if index is valid
918 845 if (i != -1) {
919 846  
920   - // Get callback port
921   - std::string client_port = get_callback_port(xml);
  847 + // Get callback URL
  848 + std::string client_url = get_callback_url(xml);
922 849  
923   - // Set callback port value
924   - sprintf(m_clients->metadata[i].port, "%s", client_port.c_str());
  850 + // Set callback URL
  851 + m_clients[i].url = get_callback_url(xml);
925 852  
926   - // Declare message
927   - std::string msg = "";
928   -
929   - // The hub response to rpc callback declaration has no useful
930   - // content and can be discarded by the client.
931   - msg.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
932   - msg.append("<methodResponse>\n");
933   - msg.append("<params>\n");
934   - msg.append(" <param><value><struct>\n");
935   - msg.append(" <member><name>samp.status</name><value>samp.ok</value></member>\n");
936   - msg.append(" </struct></value></param>\n");
937   - msg.append("</params>\n");
938   - msg.append("</methodResponse>\n");
939   -
940   - // Post message
941   - post_string(msg, sock);
  853 + // Post SAMP ok
  854 + post_samp_ok(sock);
942 855  
943 856 } // endif: client found
944 857  
  858 + // Signal if the client was unknown
  859 + #if defined(G_CONSOLE_DUMP)
  860 + else {
  861 + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl;
  862 + }
  863 + #endif
  864 +
945 865 // Return
946 866 return;
947 867 }
... ... @@ -955,7 +875,7 @@ void GVOHub::request_set_xml_rpc_callback(const GXml&amp; xml,const socklen_t&amp; sock)
955 875 *
956 876 * Handles all incoming subscriptions getting requests.
957 877 ***************************************************************************/
958   -void GVOHub::request_get_subscriptions(const GXml& xml,const socklen_t& sock)
  878 +void GVOHub::request_get_subscriptions(const GXml& xml, const socklen_t& sock)
959 879 {
960 880 // Header
961 881 #if defined(G_CONSOLE_DUMP)
... ... @@ -978,18 +898,14 @@ void GVOHub::request_get_subscriptions(const GXml&amp; xml,const socklen_t&amp; sock)
978 898 msg.append(" <param><value><struct>\n");
979 899  
980 900 // Append all subscriptions
981   - char tempo[128];
982   - for (int j = 0; j < GVOHUB_NB_METHODS; ++j) {
983   - strcpy(tempo, m_clients->metadata[i].registered_methods[j]);
984   - if (strcmp("", tempo) != 0) {
985   - msg.append(" <member>\n");
986   - msg.append(" <name>");
987   - msg.append(tempo);
988   - msg.append("</name>\n");
989   - msg.append(" <value></value>\n)");
990   - msg.append(" </member>\n");
991   - }
992   - }
  901 + for (int k = 0; k < m_clients[i].subscriptions.size(); ++k) {
  902 + msg.append(" <member>\n");
  903 + msg.append(" <name>");
  904 + msg.append(m_clients[i].subscriptions[k]);
  905 + msg.append("</name>\n");
  906 + msg.append(" <value></value>\n)");
  907 + msg.append(" </member>\n");
  908 + }
993 909  
994 910 // Finish response
995 911 msg.append(" </struct></value></param>\n");
... ... @@ -997,9 +913,16 @@ void GVOHub::request_get_subscriptions(const GXml&amp; xml,const socklen_t&amp; sock)
997 913 msg.append("</methodResponse>\n");
998 914  
999 915 // Post response
1000   - post_string(msg,sock);
  916 + post_string(msg, sock);
1001 917  
1002 918 } // endif: client index was valid
  919 +
  920 + // Signal if the client was unknown
  921 + #if defined(G_CONSOLE_DUMP)
  922 + else {
  923 + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl;
  924 + }
  925 + #endif
1003 926  
1004 927 // Return
1005 928 return;
... ... @@ -1035,13 +958,11 @@ void GVOHub::request_get_registered_clients(const GXml&amp; xml, const socklen_t&amp; so
1035 958 msg.append(" <value>gammalib_hub</value>\n");
1036 959  
1037 960 // Loop over all clients. Do not send back current client's registration
1038   - for (int i = 0; i < GVOHUB_NB_CLIENTS; ++i) {
1039   - if (strcmp(m_clients->metadata[i].reference,"NoRef") != 0) {
1040   - if (strcmp(m_clients->metadata[i].private_key, key.c_str()) != 0) {
1041   - msg.append(" <value>");
1042   - msg.append(m_clients->metadata[i].reference);
1043   - msg.append("</value>\n");
1044   - }
  961 + for (int i = 0; i < m_clients.size(); ++i) {
  962 + if (m_clients[i].private_key != key) {
  963 + msg.append(" <value>");
  964 + msg.append(m_clients[i].reference);
  965 + msg.append("</value>\n");
1045 966 }
1046 967 }
1047 968  
... ... @@ -1053,7 +974,7 @@ void GVOHub::request_get_registered_clients(const GXml&amp; xml, const socklen_t&amp; so
1053 974 // Post response
1054 975 post_string(msg, sock);
1055 976  
1056   - //Return
  977 + // Return
1057 978 return;
1058 979  
1059 980 }
... ... @@ -1107,7 +1028,7 @@ void GVOHub::request_get_subscribed_clients(const GXml&amp; xml, const socklen_t&amp; so
1107 1028 msg.append("</methodResponse>\n");
1108 1029  
1109 1030 // Post message
1110   - post_string(msg,sock);
  1031 + post_string(msg, sock);
1111 1032  
1112 1033 // Return
1113 1034 return;
... ... @@ -1168,28 +1089,28 @@ void GVOHub::request_get_metadata(const GXml&amp; xml,const socklen_t&amp; sock)
1168 1089  
1169 1090 // Append response
1170 1091 msg.append(" <member><name>samp.name</name><value>");
1171   - msg.append(m_clients->metadata[i].name);
  1092 + msg.append(m_clients[i].name);
1172 1093 msg.append("</value></member>\n");
1173 1094 msg.append(" <member><name>samp.description.text</name><value>");
1174   - msg.append(m_clients->metadata[i].description);
  1095 + msg.append(m_clients[i].description);
1175 1096 msg.append("</value></member>\n");
1176 1097 msg.append(" <member><name>samp.icon.url</name><value>");
1177   - msg.append(m_clients->metadata[i].icon);
  1098 + msg.append(m_clients[i].icon);
1178 1099 msg.append("</value></member>\n");
1179 1100 msg.append(" <member><name>samp.documentation.url</name><value>");
1180   - msg.append(m_clients->metadata[i].documentation);
  1101 + msg.append(m_clients[i].documentation);
1181 1102 msg.append("</value></member>\n");
1182 1103 msg.append(" <member><name>author.affiliation</name><value>");
1183   - msg.append(m_clients->metadata[i].affiliation);
  1104 + msg.append(m_clients[i].affiliation);
1184 1105 msg.append("</value></member>\n");
1185 1106 msg.append(" <member><name>author.email</name><value>");
1186   - msg.append(m_clients->metadata[i].email);
  1107 + msg.append(m_clients[i].email);
1187 1108 msg.append("</value></member>\n");
1188 1109 msg.append(" <member><name>author.name</name><value>");
1189   - msg.append(m_clients->metadata[i].author_name);
  1110 + msg.append(m_clients[i].author_name);
1190 1111 msg.append("</value></member>\n");
1191 1112 msg.append(" <member><name>home.page</name><value>");
1192   - msg.append(m_clients->metadata[i].homepage);
  1113 + msg.append(m_clients[i].homepage);
1193 1114 msg.append("</value></member>\n");
1194 1115  
1195 1116 } // endif: index was valid
... ... @@ -1224,21 +1145,10 @@ void GVOHub::request_shutdown(const socklen_t&amp; sock)
1224 1145 #endif
1225 1146  
1226 1147 // Set shutdown flag
1227   - m_clients->registered = -1;
  1148 + m_shutdown = true;
1228 1149  
1229   - // Declare message
1230   - std::string msg = "";
1231   -
1232   - // Set response
1233   - msg.append("<?xml version=\"1.0\"?>\n");
1234   - msg.append("<methodResponse>\n");
1235   - msg.append("<params>\n");
1236   - msg.append(" <param><value/></param>\n");
1237   - msg.append("</params>\n");
1238   - msg.append("</methodResponse>\n");
1239   -
1240   - // Post response
1241   - post_string(msg,sock);
  1150 + // Post SAMP ok
  1151 + post_samp_ok(sock);
1242 1152  
1243 1153 // Return
1244 1154 return;
... ... @@ -1300,9 +1210,9 @@ int GVOHub::get_client_index(const GXml&amp; xml) const
1300 1210 // Continue only if string is not empty
1301 1211 if (!key.empty()) {
1302 1212  
1303   - // Searches for key in metadata
1304   - for (int i = 0; i < GVOHUB_NB_CLIENTS; ++i) {
1305   - if (strcmp(m_clients->metadata[i].private_key, key.c_str()) == 0) {
  1213 + // Searches for key in clients
  1214 + for (int i = 0; i < m_clients.size(); ++i) {
  1215 + if (m_clients[i].private_key == key) {
1306 1216 index = i;
1307 1217 break;
1308 1218 }
... ... @@ -1400,18 +1310,18 @@ void GVOHub::get_name_value_pair(const GXmlNode* node,
1400 1310  
1401 1311  
1402 1312 /***********************************************************************//**
1403   - * @brief Returns registrations from XML document
  1313 + * @brief Returns subscriptions from XML document
1404 1314 *
1405 1315 * @param[in] xml client query XML document.
1406   - * @return List of registrations.
  1316 + * @return List of subscriptions.
1407 1317 ***************************************************************************/
1408   -std::list<std::string> GVOHub::get_registrations(const GXml& xml) const
  1318 +std::vector<std::string> GVOHub::get_subscriptions(const GXml& xml) const
1409 1319 {
1410   - // Declare value
1411   - std::list<std::string> value;
  1320 + // Declare subscriptions
  1321 + std::vector<std::string> subscriptions;
1412 1322  
1413 1323 // Get the client's private key
1414   - const GXmlNode* node = xml.element("methodCall > params > param > value > struct");
  1324 + const GXmlNode* node = xml.element("methodCall > params > param[1] > value > struct");
1415 1325 if (node != NULL) {
1416 1326 int num = node->elements("member");
1417 1327 for (int i = 0; i < num; ++i) {
... ... @@ -1421,40 +1331,40 @@ std::list&lt;std::string&gt; GVOHub::get_registrations(const GXml&amp; xml) const
1421 1331 if (name != NULL) {
1422 1332 const GXmlText* text = static_cast<const GXmlText*>((*name)[0]);
1423 1333 if (text != NULL) {
1424   - value.push_front(text->text());
  1334 + subscriptions.push_back(text->text());
1425 1335 }
1426 1336 }
1427 1337 }
1428 1338 }
1429 1339 }
1430 1340  
1431   - // Return value
1432   - return value;
  1341 + // Return subscriptions
  1342 + return subscriptions;
1433 1343 }
1434 1344  
1435 1345  
1436 1346 /***********************************************************************//**
1437   - * @brief Returns callback port
  1347 + * @brief Returns callback URL of client
1438 1348 *
1439 1349 * @param[in] xml client query XML document.
1440   - * @return Callback port value.
  1350 + * @return Callback URL of client.
1441 1351 ***************************************************************************/
1442   -std::string GVOHub::get_callback_port(const GXml& xml) const
  1352 +std::string GVOHub::get_callback_url(const GXml& xml) const
1443 1353 {
1444   - // Declare value
1445   - std::string value;
  1354 + // Declare URL
  1355 + std::string url;
1446 1356  
1447 1357 // Get the client's private key
1448 1358 const GXmlNode* node = xml.element("methodCall > params > param[1] > value");
1449 1359 if (node != NULL) {
1450 1360 const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
1451 1361 if (text != NULL) {
1452   - value.append(text->text());
  1362 + url.append(text->text());
1453 1363 }
1454 1364 }
1455 1365  
1456   - // Return value
1457   - return value;
  1366 + // Return URL
  1367 + return url;
1458 1368 }
1459 1369  
1460 1370  
... ... @@ -1510,186 +1420,188 @@ std::string GVOHub::get_hub_lockfile(void) const
1510 1420  
1511 1421  
1512 1422 /***********************************************************************//**
1513   - * @brief Test if any registered client needs to know that the method
1514   - * has been called
  1423 + * @brief Send notifications
1515 1424 *
1516   - * @param[in] method: name of the method
1517   - * @param[in] cl_id id of calling client
  1425 + * @param[in] method Name of the method
  1426 + * @param[in] client Reference of the client
  1427 + *
  1428 + * The method send notifications to all registered clients that request so.
1518 1429 ***************************************************************************/
1519   -void GVOHub::activate_callbacks(std::string method,char cl_id[31])
  1430 +void GVOHub::send_notifications(const std::string& method,
  1431 + const std::string& client)
1520 1432 {
1521   - int k;
1522   - char port[16];
1523   - char pkey[16];
1524   - std::string spkey;
1525   -
1526 1433 // Loop over all clients
1527   - for (int i = 0; i < GVOHUB_NB_CLIENTS; ++i) {
  1434 + for (int i = 0; i < m_clients.size(); ++i) {
1528 1435  
1529 1436 // Loop over all methods
1530   - for (int j = 0; j < GVOHUB_NB_METHODS; ++j) {
  1437 + for (int j = 0; j < m_clients[i].subscriptions.size(); ++j) {
  1438 +
  1439 + // Continue only if method matches
  1440 + if (method == m_clients[i].subscriptions[j]) {
1531 1441  
1532   - // Continue only if method is valid
1533   - if (strcmp("",m_clients->metadata[i].registered_methods[j]) != 0) {
1534   -
1535   - //
1536   - if (strcmp(method.c_str(), m_clients->metadata[i].registered_methods[j]) == 0) {
1537   - strcpy(port,m_clients->metadata[i].port);
1538   - std::string port_string = std::string(port);
1539   - //Eliminate http://127.0.0.1/ from port string -----> improve this code is necessary
1540   - port_string.replace(0,17,"");
1541   - std::size_t pos = port_string.find("/");
1542   - std::string port_only = port_string.substr(0,pos);
1543   -
1544   - // Set hints
1545   - struct addrinfo hints;
1546   - std::memset(&hints, 0, sizeof(hints));
1547   - hints.ai_family = AF_INET;
1548   - hints.ai_socktype = SOCK_STREAM;
1549   -
1550   - // Get server information
1551   - struct addrinfo* servinfo;
1552   - if (getaddrinfo("127.0.0.1", port_only.c_str(),
1553   - &hints, &servinfo) == 0) {
1554   -
1555   - // Loop through all the results and connect to the first
1556   - // we can
1557   - for (struct addrinfo* ptr = servinfo; ptr != NULL; ptr = ptr->ai_next) {
1558   -
1559   - // Create socket
1560   - m_cback_socket = socket(ptr->ai_family,
1561   - ptr->ai_socktype,
1562   - ptr->ai_protocol);
1563   -
1564   - // Connect to socket if socket is valid
1565   - if (m_cback_socket != -1) {
1566   - if (::connect(m_cback_socket,
1567   - ptr->ai_addr,
1568   - ptr->ai_addrlen) == -1) {
1569   - close(m_cback_socket);
1570   - m_cback_socket = -1;
1571   - }
1572   - }
1573   -
1574   - } // endfor: looped through all results
1575   -
1576   - } // endif: server information was valid
1577   -
1578   - //
1579   - std::string msg = "";
1580   -
1581   - //
1582   - if (strcmp(method.c_str(),"samp.hub.event.register") == 0) {
1583   -
1584   - // Set methodResponse elts for samp.hub.event.register
1585   - msg.append("<?xml version=\"1.0\"?>\n");
1586   - msg.append("<methodCall><methodName>samp.client.receiveNotification</methodName>\n");
1587   - msg.append("\t<params>\n");
1588   - msg.append("\t\t<param><value>");
1589   - msg.append(m_clients->metadata[i].private_key);
1590   - msg.append("</value></param>\n");
1591   - msg.append("\t\t<param><value>"+m_hub_id+"</value></param>\n");
1592   - msg.append("\t\t<param>\n\t\t\t<value>\n\t\t\t\t<struct>\n");
1593   - msg.append("\t\t\t\t\t<member><name>samp.mtype</name><value>samp.hub.event.register</value></member>\n");
1594   - msg.append("\t\t\t\t\t<member><name>samp.params</name><value>\n\t\t\t\t\t\t<struct>\n\t\t\t\t\t\t\t<member>");
1595   - msg.append("<name>id</name><value>");
1596   - msg.append(cl_id);
1597   - msg.append("</value></member>\n\t\t\t\t\t\t</struct>\n\t\t\t\t\t</value></member>\n");
1598   - msg.append("\t\t\t\t</struct>\n\t\t\t</value>\n\t\t</param>\n");
1599   - msg.append("\t</params>\n");
1600   - msg.append("</methodCall>\n");
  1442 + // Declare notification
  1443 + std::string msg = "";
  1444 +
  1445 + // Register
  1446 + if (method == "samp.hub.event.register") {
  1447 +
  1448 + // Set response for samp.hub.event.register
  1449 + msg.append("<?xml version=\"1.0\"?>\n");
  1450 + msg.append("<methodCall>\n");
  1451 + msg.append("<methodName>samp.client.receiveNotification</methodName>\n");
  1452 + msg.append("<params>\n");
  1453 + msg.append(" <param><value>");
  1454 + msg.append(m_clients[i].private_key);
  1455 + msg.append("</value></param>\n");
  1456 + msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
  1457 + msg.append(" <param><value><struct>\n");
  1458 + msg.append(" <member>\n");
  1459 + msg.append(" <name>samp.mtype</name>\n");
  1460 + msg.append(" <value>samp.hub.event.register</value>\n");
  1461 + msg.append(" </member>\n");
  1462 + msg.append(" <member>\n");
  1463 + msg.append(" <name>samp.params</name>\n");
  1464 + msg.append(" <value><struct>\n");
  1465 + msg.append(" <member>\n");
  1466 + msg.append(" <name>id</name>\n");
  1467 + msg.append(" <value>"+client+"</value>\n");
  1468 + msg.append(" </member>\n");
  1469 + msg.append(" </struct></value>\n");
  1470 + msg.append(" </member>\n");
  1471 + msg.append(" </struct></value></param>\n");
  1472 + msg.append("</params>\n");
  1473 + msg.append("</methodCall>\n");
1601 1474  
1602   - // Post response
1603   - post_string_callback(msg);
  1475 + // Post notification
  1476 + notify(m_clients[i].url, msg);
1604 1477  
1605   - }
  1478 + }
1606 1479  
1607   - //
1608   - else if (strcmp(method.c_str(),"samp.hub.event.unregister") == 0) {
1609   -
1610   - // Set methodResponse elts for samp.hub.event.unregister
1611   - msg.append("<?xml version=\"1.0\"?>\n");
1612   - msg.append("<methodCall><methodName>samp.client.receiveNotification</methodName>\n");
1613   - msg.append("\t<params>\n");
1614   - msg.append("\t\t<param><value>");
1615   - msg.append(m_clients->metadata[i].private_key);
1616   - msg.append("</value></param>\n");
1617   - msg.append("\t\t<param><value>"+m_hub_id+"</value></param>\n");
1618   - msg.append("\t\t<param>\n\t\t\t<value>\n\t\t\t\t<struct>\n");
1619   - msg.append("\t\t\t\t\t<member><name>samp.mtype</name><value>samp.hub.event.unregister</value></member>\n");
1620   - msg.append("\t\t\t\t\t<member><name>samp.params</name><value>\n\t\t\t\t\t\t<struct>\n\t\t\t\t\t\t\t<member>");
1621   - msg.append("<name>id</name><value>");
1622   - msg.append(cl_id);
1623   - msg.append("</value></member>\n\t\t\t\t\t\t</struct>\n\t\t\t\t\t</value></member>\n");
1624   - msg.append("\t\t\t\t</struct>\n\t\t\t</value>\n\t\t</param>\n");
1625   - msg.append("\t</params>\n");
1626   - msg.append("</methodCall>\n");
  1480 + // Unregister
  1481 + else if (method == "samp.hub.event.unregister") {
  1482 +
  1483 + // Set response for samp.hub.event.unregister
  1484 + msg.append("<?xml version=\"1.0\"?>\n");
  1485 + msg.append("<methodCall>\n");
  1486 + msg.append("<methodName>samp.client.receiveNotification</methodName>\n");
  1487 + msg.append("<params>\n");
  1488 + msg.append(" <param><value>");
  1489 + msg.append(m_clients[i].private_key);
  1490 + msg.append("</value></param>\n");
  1491 + msg.append(" <param><value>");
  1492 + msg.append(m_hub_id);
  1493 + msg.append("</value></param>\n");
  1494 + msg.append(" <param><value><struct>\n");
  1495 + msg.append(" <member>\n");
  1496 + msg.append(" <name>samp.mtype</name>\n");
  1497 + msg.append(" <value>samp.hub.event.unregister</value>\n");
  1498 + msg.append(" </member>\n");
  1499 + msg.append(" <member>\n");
  1500 + msg.append(" <name>samp.params</name>\n");
  1501 + msg.append(" <value><struct>\n");
  1502 + msg.append(" <member>\n");
  1503 + msg.append(" <name>id</name>\n");
  1504 + msg.append(" <value>"+client+"</value>\n");
  1505 + msg.append(" </member>\n");
  1506 + msg.append(" </struct></value>\n");
  1507 + msg.append(" </member>\n");
  1508 + msg.append(" </struct></value></param>\n");
  1509 + msg.append("</params>\n");
  1510 + msg.append("</methodCall>\n");
1627 1511  
1628   - // Post response
1629   - post_string_callback(msg);
  1512 + // Post notification
  1513 + notify(m_clients[i].url, msg);
1630 1514  
1631   - }
  1515 + }
1632 1516  
1633   - //
1634   - else if (strcmp(method.c_str(),"samp.hub.event.metadata") == 0) {
1635   -
1636   - // Set methodResponse elts for samp.hub.event.unregister
1637   - msg.append("<?xml version=\"1.0\"?>\n");
1638   - msg.append("<methodCall><methodName>samp.client.receiveNotification</methodName>\n");
1639   - msg.append("\t<params>\n");
1640   - msg.append("\t\t<param><value>");
1641   - msg.append(m_clients->metadata[i].private_key);
1642   - msg.append("</value></param>\n");
1643   - msg.append("\t\t<param><value>"+m_hub_id+"</value></param>\n");
1644   - msg.append("\t\t<param>\n\t\t\t<value>\n\t\t\t\t<struct>\n");
1645   - msg.append("\t\t\t\t\t<member><name>samp.mtype</name><value>samp.hub.event.metadata</value></member>\n");
1646   - msg.append("\t\t\t\t\t<member><name>samp.params</name><value>\n\t\t\t\t\t\t<struct>\n\t\t\t\t\t\t\t");
1647   - msg.append("\t\t\t\t\t<member><name>id</name><value>");
1648   - for (k = 0; k < GVOHUB_NB_CLIENTS; k++) {
1649   - if (strcmp(cl_id,m_clients->metadata[k].reference) == 0) {
1650   - break;
1651   - }
  1517 + // Metadata
  1518 + else if (method == "samp.hub.event.metadata") {
  1519 +
  1520 + // Get index of client
  1521 + int k;
  1522 + for (k = 0; k < m_clients.size(); ++k) {
  1523 + if (m_clients[k].reference == client) {
  1524 + break;
1652 1525 }
1653   - msg.append(m_clients->metadata[k].reference);
1654   - msg.append("</value>\n\t\t\t\t\t</member>\n");
1655   - msg.append("\t\t\t\t\t<member><name>metadata</name><value>\n\t\t\t\t\t\t<struct>\n\t\t\t\t\t\t\t");
1656   - msg.append("\t\t\t\t\t<member>\n\t\t\t\t\t\t<name>samp.name</name>\n\t\t\t\t\t\t<value>");
1657   - msg.append(m_clients->metadata[k].name);
1658   - msg.append("</value>\n\t\t\t\t\t</member>\n");
1659   - msg.append("\t\t\t\t\t<member>\n\t\t\t\t\t\t<name>samp.description.text</name>\n\t\t\t\t\t\t<value>");
1660   - msg.append(m_clients->metadata[k].description);
1661   - msg.append("</value>\n\t\t\t\t\t</member>\n");
1662   - msg.append("\t\t\t\t\t<member>\n\t\t\t\t\t\t<name>samp.icon.url</name>\n\t\t\t\t\t\t<value>");
1663   - msg.append(m_clients->metadata[k].icon);
1664   - msg.append("</value>\n\t\t\t\t\t</member>\n");
1665   - msg.append("\t\t\t\t\t<member>\n\t\t\t\t\t\t<name>samp.documentation.url</name>\n\t\t\t\t\t\t<value>");
1666   - msg.append(m_clients->metadata[k].documentation);
1667   - msg.append("</value>\n\t\t\t\t\t</member>\n");
1668   - msg.append("\t\t\t\t\t<member>\n\t\t\t\t\t\t<name>author.affiliation</name>\n\t\t\t\t\t\t<value>");
1669   - msg.append(m_clients->metadata[k].affiliation);
1670   - msg.append("</value>\n\t\t\t\t\t</member>\n");
1671   - msg.append("\t\t\t\t\t<member>\n\t\t\t\t\t\t<name>author.email</name>\n\t\t\t\t\t\t<value>");
1672   - msg.append(m_clients->metadata[k].email);
1673   - msg.append("</value>\n\t\t\t\t\t</member>\n");
1674   - msg.append("\t\t\t\t\t<member>\n\t\t\t\t\t\t<name>author.name</name>\n\t\t\t\t\t\t<value>");
1675   - msg.append(m_clients->metadata[k].author_name);
1676   - msg.append("</value>\n\t\t\t\t\t</member>\n");
1677   - msg.append("\t\t\t\t\t<member>\n\t\t\t\t\t\t<name>home.page</name>\n\t\t\t\t\t\t<value>");
1678   - msg.append(m_clients->metadata[k].homepage);
1679   - msg.append("</value>\n\t\t\t\t\t</member>\n");
1680   - msg.append("</struct></value></member>\n");
1681   - msg.append("</struct>\n\t\t\t\t\t</value></member>\n");
1682   - msg.append("\t\t\t\t</struct>\n\t\t\t</value>\n\t\t</param>\n");
1683   - msg.append("\t</params>\n");
1684   - msg.append("</methodCall>\n");
  1526 + }
  1527 +
  1528 + // Fall through if client index is not valid
  1529 + if (k >= m_clients.size()) {
  1530 + continue;
  1531 + }
  1532 +
  1533 + // Set response for samp.hub.event.metadata
  1534 + msg.append("<?xml version=\"1.0\"?>\n");
  1535 + msg.append("<methodCall><methodName>samp.client.receiveNotification</methodName>\n");
  1536 + msg.append("<params>\n");
  1537 + msg.append(" <param><value>");
  1538 + msg.append(m_clients[i].private_key);
  1539 + msg.append("</value></param>\n");
  1540 + msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
  1541 + msg.append(" <param><value><struct>\n");
  1542 + msg.append(" <member>\n");
  1543 + msg.append(" <name>samp.mtype</name>\n");
  1544 + msg.append(" <value>samp.hub.event.metadata</value>\n");
  1545 + msg.append(" </member>\n");
  1546 + msg.append(" <member>\n");
  1547 + msg.append(" <name>samp.params</name>\n");
  1548 + msg.append(" <value><struct>\n");
  1549 + msg.append(" <member>\n");
  1550 + msg.append(" <name>id</name>\n");
  1551 + msg.append(" <value>"+m_clients[k].reference+"</value>\n");
  1552 + msg.append(" </member>\n");
  1553 + msg.append(" <member>\n");
  1554 + msg.append(" <name>metadata</name>\n");
  1555 + msg.append(" <value><struct>\n");
  1556 + msg.append(" <member>\n");
  1557 + msg.append(" <name>samp.name</name>\n");
  1558 + msg.append(" <value>"+m_clients[k].name+"</value>\n");
  1559 + msg.append(" </member>\n");
  1560 + msg.append(" <member>\n");
  1561 + msg.append(" <name>samp.description.text</name>\n");
  1562 + msg.append(" <value>"+m_clients[k].description+"</value>\n");
  1563 + msg.append(" </member>\n");
  1564 + msg.append(" <member>\n");
  1565 + msg.append(" <name>samp.icon.url</name>\n");
  1566 + msg.append(" <value>"+m_clients[k].icon+"</value>\n");
  1567 + msg.append(" </member>\n");
  1568 + msg.append(" <member>\n");
  1569 + msg.append(" <name>samp.documentation.url</name>\n");
  1570 + msg.append(" <value>"+m_clients[k].documentation+"</value>\n");
  1571 + msg.append(" </member>\n");
  1572 + msg.append(" <member>\n");
  1573 + msg.append(" <name>author.affiliation</name>\n");
  1574 + msg.append(" <value>"+m_clients[k].affiliation+"</value>\n");
  1575 + msg.append(" </member>\n");
  1576 + msg.append(" <member>\n");
  1577 + msg.append(" <name>author.name</name>\n");
  1578 + msg.append(" <value>"+m_clients[k].author_name+"</value>\n");
  1579 + msg.append(" </member>\n");
  1580 + msg.append(" <member>\n");
  1581 + msg.append(" <name>author.email</name>\n");
  1582 + msg.append(" <value>"+m_clients[k].email+"</value>\n");
  1583 + msg.append(" </member>\n");
  1584 + msg.append(" <member>\n");
  1585 + msg.append(" <name>home.page</name>\n");
  1586 + msg.append(" <value>"+m_clients[k].homepage+"</value>\n");
  1587 + msg.append(" </member>\n");
  1588 + msg.append(" </struct></value>\n");
  1589 + msg.append(" </member>\n");
  1590 + msg.append(" </struct></value>\n");
  1591 + msg.append(" </member>\n");
  1592 + msg.append(" </struct></value></param>\n");
  1593 + msg.append("</params>\n");
  1594 + msg.append("</methodCall>\n");
1685 1595  
1686   - // Post response
1687   - post_string_callback(msg);
  1596 + // Post notification
  1597 + notify(m_clients[i].url, msg);
1688 1598  
1689   - }
1690   - }
1691   - } // endif: method was valid
  1599 + } // endelse: metadata
  1600 +
  1601 + } // endif: method was requested one
  1602 +
1692 1603 } // endfor: looped over all methods
  1604 +
1693 1605 } // endfor: looped over all clients
1694 1606  
1695 1607 // Return
... ... @@ -1709,37 +1621,61 @@ void GVOHub::create_samp_file(void) const
1709 1621  
1710 1622 // Open SAMP lockfile. Continue only if opening was successful
1711 1623 FILE* fptr = fopen(lockurl.c_str(), "w");
  1624 +
  1625 + // Successful?
1712 1626 if (fptr != NULL) {
1713 1627  
1714   - // If successful writes basic hub configuration to the lockfile
1715   - fputs("# SAMP lockfile \n# Required keys:\n",fptr);
1716   - char sampsecret[256] = "samp.secret=";
1717   - strcat(sampsecret,m_secret.c_str());
1718   - strcat(sampsecret,"\n");
1719   - fputs (sampsecret,fptr);
1720   - char sampurl[256] = "samp.hub.xmlrpc.url=";
1721   - strcat(sampurl,m_hub_url.c_str());
1722   - strcat(sampurl,"\n");
1723   - fputs(sampurl,fptr);
1724   - char samprofile[256] = "samp.profile.version=";
1725   - strcat(samprofile,m_version.c_str());
1726   - strcat(samprofile,"\n");
1727   - fputs(samprofile,fptr);
1728   - fputs("# Info stored by hub for some private reason:\n",fptr);
1729   - char sampid[256] = "gammalib.hubid=";
1730   - strcat(sampid,m_hub_id.c_str());
1731   - strcat(sampid,"\n");
1732   - fputs(sampid,fptr);
  1628 + // Write lockfile
  1629 + fprintf(fptr, "# SAMP lockfile\n");
  1630 + fprintf(fptr, "# Required keys:\n");
  1631 + fprintf(fptr, "samp.secret=%s\n", m_secret.c_str());
  1632 + fprintf(fptr, "samp.hub.xmlrpc.url=%s\n", m_hub_url.c_str());
  1633 + fprintf(fptr, "samp.profile.version=%s\n", m_version.c_str());
  1634 + fprintf(fptr, "# Info stored by hub for some private reason:\n");
  1635 + fprintf(fptr, "gammalib.hubid=%s\n", m_hub_id.c_str());
  1636 +
  1637 + // Close lockfile
  1638 + fclose(fptr);
  1639 +
1733 1640 }
1734   -
1735   - // Close SAMP lockfile
1736   - fclose(fptr);
1737 1641  
1738 1642 // Return
1739 1643 return;
1740 1644 }
1741 1645  
1742 1646  
  1647 +/***********************************************************************//**
  1648 + * @brief Post SAMP ok massage to client
  1649 + *
  1650 + * @param[in] sock Socket.
  1651 + *
  1652 + * Posts a SAMP of massage to a client.
  1653 + ***************************************************************************/
  1654 +void GVOHub::post_samp_ok(const socklen_t& sock) const
  1655 +{
  1656 + // Declare response
  1657 + std::string response = "";
  1658 +
  1659 + // Compose response
  1660 + response.append("<?xml version='1.0' encoding='UTF-8'?>\n");
  1661 + response.append("<methodResponse>\n");
  1662 + response.append("<params>\n");
  1663 + response.append(" <param><value><struct>\n");
  1664 + response.append(" <member>\n");
  1665 + response.append(" <name>samp.status</name>\n");
  1666 + response.append(" <value>samp.ok</value>\n");
  1667 + response.append(" </member>\n");
  1668 + response.append(" </struct></value></param>\n");
  1669 + response.append("</params>\n");
  1670 + response.append("</methodResponse>\n");
  1671 +
  1672 + // Post string
  1673 + post_string(response, sock);
  1674 +
  1675 + // Return
  1676 + return;
  1677 +}
  1678 +
1743 1679  
1744 1680 /***********************************************************************//**
1745 1681 * @brief Post string content to client
... ... @@ -1749,7 +1685,7 @@ void GVOHub::create_samp_file(void) const
1749 1685 *
1750 1686 * Posts the content of a string to a client.
1751 1687 ***************************************************************************/
1752   -void GVOHub::post_string(const std::string& content,const socklen_t& sock) const
  1688 +void GVOHub::post_string(const std::string& content, const socklen_t& sock) const
1753 1689 {
1754 1690 // Continue only if socket is valid
1755 1691 if (sock != -1) {
... ... @@ -1758,18 +1694,26 @@ void GVOHub::post_string(const std::string&amp; content,const socklen_t&amp; sock) const
1758 1694 int length = content.length();
1759 1695  
1760 1696 // Set prefix
1761   - std::string prefix = "HTTP/1.1 200 OK\n"
1762   - "Connection: close\n"
  1697 + std::string prefix = "POST /"+m_hub_path+" HTTP/1.1\n"
1763 1698 "Content-Type: text/xml\n"
  1699 + "User-Agent: GammaLib\n"
  1700 + "Host: "+m_hub_host+":"+m_hub_port+"\n"
  1701 + "Connection: close\n"
1764 1702 "Content-Length: "+gammalib::str(length)+"\n\n";
1765 1703  
1766 1704 // Build post string
1767 1705 std::string post = prefix + content;
1768 1706  
  1707 + // Dump message to post
  1708 + #if defined(G_CONSOLE_DUMP)
  1709 + std::cout << "\nGVOHub::post_string posts the following message" << std::endl;
  1710 + std::cout << post << std::endl;
  1711 + #endif
  1712 +
1769 1713 // Send content to socket
1770 1714 bool done = false;
1771 1715 do {
1772   - int length = post.length();
  1716 + int length = post.length() + 1; // +1 for terminating 0
1773 1717 int sent_length = send(sock, post.c_str(), length, 0);
1774 1718 if (sent_length < length) {
1775 1719 post = post.substr(sent_length, std::string::npos);
... ... @@ -1787,38 +1731,116 @@ void GVOHub::post_string(const std::string&amp; content,const socklen_t&amp; sock) const
1787 1731  
1788 1732  
1789 1733 /***********************************************************************//**
1790   - * @brief Post string content to client for callback
1791   - *
1792   - * @param[in] content String content to post
  1734 + * @brief Send notification to client
1793 1735 *
1794   - * Posts the content of a string to the client for a callback.
  1736 + * @param[in] url URL.
  1737 + * @param[in] notification Notification.
1795 1738 *
1796   - * The method does nothing if no callback socket is open.
  1739 + * Send a @p notification to a @p url.
1797 1740 ***************************************************************************/
1798   -void GVOHub::post_string_callback(const std::string& content) const
  1741 +void GVOHub::notify(const std::string& url,
  1742 + const std::string& notification) const
1799 1743 {
1800   - // Continue only if Hub connection has been established
1801   - if (m_cback_socket != -1) {
  1744 + // Initalise socket
  1745 + int socket = -1;
  1746 +
  1747 + // Extract host, port and path from URL
  1748 + std::string host = "127.0.0.1";
  1749 + std::string port = "2525";
  1750 + std::string path = "xmlrpc";
  1751 + if (url.compare(0, 7, "http://") == 0) {
  1752 + size_t length;
  1753 + size_t start = 7;
  1754 + size_t stop = url.find(":", start);
  1755 + size_t end = std::string::npos;
  1756 + if (stop != std::string::npos) {
  1757 + length = stop - start;
  1758 + }
  1759 + else {
  1760 + length = std::string::npos;
  1761 + }
  1762 + host = url.substr(start, length);
  1763 + if (stop != std::string::npos) {
  1764 + stop++;
  1765 + end = url.find("/", stop);
  1766 + if (end != std::string::npos) {
  1767 + length = end - stop;
  1768 + }
  1769 + else {
  1770 + length = std::string::npos;
  1771 + }
  1772 + port = url.substr(stop, length);
  1773 + }
  1774 + if (end != std::string::npos) {
  1775 + end++;
  1776 + length = url.length() - end;
  1777 + path = url.substr(end, length);
  1778 + }
  1779 + }
1802 1780  
1803   - // Determine content length
1804   - int length = content.length();
  1781 + // Set hints
  1782 + struct addrinfo hints;
  1783 + std::memset(&hints, 0, sizeof(hints));
  1784 + hints.ai_family = AF_INET;
  1785 + hints.ai_socktype = SOCK_STREAM;
  1786 +
  1787 + // Get server information
  1788 + struct addrinfo* servinfo;
  1789 + if (getaddrinfo(host.c_str(), port.c_str(), &hints, &servinfo) == 0) {
  1790 +
  1791 + // Loop through all the results and connect to the first we can
  1792 + for (struct addrinfo* ptr = servinfo; ptr != NULL; ptr = ptr->ai_next) {
  1793 +
  1794 + // Create socket
  1795 + socket = ::socket(ptr->ai_family,
  1796 + ptr->ai_socktype,
  1797 + ptr->ai_protocol);
  1798 +
  1799 + // Connect to socket if socket is valid
  1800 + if (socket != -1) {
  1801 + if (::connect(socket,
  1802 + ptr->ai_addr,
  1803 + ptr->ai_addrlen) == -1) {
  1804 + close(socket);
  1805 + socket = -1;
  1806 + }
  1807 + else {
  1808 + // Socket connection successful, break now
  1809 + break;
  1810 + }
  1811 + }
  1812 +
  1813 + } // endfor: looped through all results
  1814 +
  1815 + } // endif: server information was valid
  1816 +
  1817 + // Continue only if socket is valid
  1818 + if (socket != -1) {
  1819 +
  1820 + // Determine notification length
  1821 + int length = notification.length();
1805 1822  
1806 1823 // Set prefix
1807   - std::string prefix = "POST /xmlrpc HTTP/1.1\n"
1808   - "Connection: keep-alive\n"
  1824 + std::string prefix = "POST /"+path+" HTTP/1.0\n"
  1825 + "Connection: close\n"
1809 1826 "User-Agent: GammaLib\n"
1810   - "Host: localhost:"+gammalib::str(m_cback_socket)+"\n"
1811 1827 "Content-Type: text/xml\n"
1812 1828 "Content-Length: "+gammalib::str(length)+"\n\n";
1813 1829  
1814 1830 // Build post string
1815   - std::string post = prefix + content;
  1831 + std::string post = prefix + notification;
  1832 +
  1833 + // Dump message to post
  1834 + #if defined(G_CONSOLE_DUMP)
  1835 + std::cout << "\nGVOHub::notify posts the following message" << std::endl;
  1836 + std::cout << post << std::endl;
  1837 + #endif
1816 1838  
1817 1839 // Send content to socket
1818 1840 bool done = false;
1819 1841 do {
1820   - int length = post.length();
1821   - int sent_length = send(m_cback_socket, post.c_str(), length, 0);
  1842 + int length = post.length() + 1; // +1 for terminating 0
  1843 + int sent_length = send(socket, post.c_str(), length, 0);
1822 1844 if (sent_length < length) {
1823 1845 post = post.substr(sent_length, std::string::npos);
1824 1846 }
... ... @@ -1827,20 +1849,29 @@ void GVOHub::post_string_callback(const std::string&amp; content) const
1827 1849 }
1828 1850 } while (!done);
1829 1851  
  1852 + /*
  1853 + // Declare response
  1854 + std::string response = "";
  1855 +
1830 1856 // Read buffer until it is empty
1831 1857 char buffer[1001];
1832   - int timeout = 2000; // Initial timeout is 2 sec
  1858 + int timeout = 1000; // Initial timeout is 1 sec
1833 1859 int n = 0;
1834 1860 do {
1835   - n = gammalib::recv(m_cback_socket, buffer, 1000, 0, timeout);
  1861 + n = gammalib::recv(socket, buffer, 1000, 0, timeout);
1836 1862 if (n > 0) {
1837 1863 buffer[n+1] = '\0';
  1864 + response.append(std::string(buffer));
1838 1865 }
1839 1866 timeout = 10; // The timeout now is 0.01 sec
1840 1867 } while (n > 0);
  1868 + */
  1869 +
  1870 + // Close socket
  1871 + close(socket);
  1872 +
  1873 + }
1841 1874  
1842   - } // endif: Hub connection had been established
1843   -
1844 1875 // Return
1845 1876 return;
1846 1877 }
... ...