GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GVOHub.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GVOHub.cpp - VO SAMP Hub class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2014-2020 by Thierry Louge *
5  * ----------------------------------------------------------------------- *
6  * *
7  * This program is free software: you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation, either version 3 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19  * *
20  ***************************************************************************/
21 /**
22  * @file GVOHub.cpp
23  * @brief VO SAMP Hub class implementation
24  * @author Thierry Louge
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <cstdlib> // std::getenv() function
32 #include <cstdio> // std::fopen(), etc. functions
33 #include <cstring> // std::memset() function
34 #include <csignal> // signal() function
35 #include <cerrno> // errno
36 #include <unistd.h> // close() function
37 #include <netdb.h> // getaddrinfo() function
38 #include <netinet/in.h> // sockaddr_in, INADDR_ANY, htons
39 #include <fstream>
40 #include <sys/shm.h>
41 #include <sys/socket.h> // socket(), connect() functions
42 #include <sys/wait.h> // waitpid() function
43 #include <arpa/inet.h> // inet_addr() function
44 #include "GTools.hpp"
45 #include "GException.hpp"
46 #include "GXml.hpp"
47 #include "GXmlNode.hpp"
48 #include "GVOHub.hpp"
49 
50 /* __ Method name definitions ____________________________________________ */
51 #define G_START_HUB "GVOHub::start_hub()"
52 #define G_GET_SOCKET "GVOHub::get_socket()"
53 
54 /* __ Macros _____________________________________________________________ */
55 
56 /* __ Coding definitions _________________________________________________ */
57 
58 /* __ Debug definitions __________________________________________________ */
59 //#define G_CONSOLE_DUMP //!< Show method headers
60 //#define G_CONSOLE_ERRORS //!< Show error messages
61 //#define G_SHOW_MESSAGE //!< Show posted and received messages
62 
63 
64 /*==========================================================================
65  = =
66  = Constructors/destructors =
67  = =
68  ==========================================================================*/
69 
70 /***********************************************************************//**
71  * @brief Void constructor
72  ***************************************************************************/
74 {
75  // Initialise members
76  init_members();
77 
78  // Return
79  return;
80 }
81 
82 
83 /***********************************************************************//**
84  * @brief Copy constructor
85  *
86  * @param[in] hub VO Hub.
87  ***************************************************************************/
89 {
90  // Initialise members
91  init_members();
92 
93  // Copy members
94  copy_members(hub);
95 
96  // Return
97  return;
98 }
99 
100 
101 /***********************************************************************//**
102  * @brief Destructor
103  ***************************************************************************/
105 {
106  // Free members
107  free_members();
108 
109  // Return
110  return;
111 }
112 
113 
114 /*==========================================================================
115  = =
116  = Operators =
117  = =
118  ==========================================================================*/
119 
120 /***********************************************************************//**
121  * @brief Assignment operator
122  *
123  * @param[in] hub VO hub.
124  * @return VO hub.
125  ***************************************************************************/
127 {
128  // Execute only if object is not identical
129  if (this != &hub) {
130 
131  // Free members
132  free_members();
133 
134  // Initialise members
135  init_members();
136 
137  // Copy members
138  copy_members(hub);
139 
140  } // endif: object was not identical
141 
142  // Return
143  return *this;
144 }
145 
146 
147 /*==========================================================================
148  = =
149  = Public methods =
150  = =
151  ==========================================================================*/
152 
153 /***********************************************************************//**
154  * @brief Clear object.
155  *
156  * Reset object to a clean initial state.
157  ***************************************************************************/
158 void GVOHub::clear(void)
159 {
160  // Free members
161  free_members();
162 
163  // Initialise members
164  init_members();
165 
166  // Return
167  return;
168 }
169 
170 
171 /***********************************************************************//**
172  * @brief Clone object
173  ***************************************************************************/
174 GVOHub* GVOHub::clone(void) const
175 {
176  // Clone client
177  return new GVOHub(*this);
178 }
179 
180 
181 /***********************************************************************//**
182  * @brief Start Hub
183  ***************************************************************************/
184 void GVOHub::start(void)
185 {
186  // Start Hub
187  start_hub();
188 
189  // Return
190  return;
191 }
192 
193 
194 /***********************************************************************//**
195  * @brief Print VO hub information
196  *
197  * @param[in] chatter Chattiness (defaults to NORMAL).
198  * @return String containing VO hub information
199  ***************************************************************************/
200 std::string GVOHub::print(const GChatter& chatter) const
201 {
202  // Initialise result string
203  std::string result;
204 
205  // Continue only if chatter is not silent
206  if (chatter != SILENT) {
207 
208  // Append header
209  result.append("=== GVOHub ===");
210 
211  // Append Hub information
212  result.append("\n"+gammalib::parformat("Hub identifier")+m_hub_id);
213  result.append("\n"+gammalib::parformat("Hub key")+m_secret);
214  result.append("\n"+gammalib::parformat("Hub URL")+hub_url());
215  result.append("\n"+gammalib::parformat("Hub host")+m_hub_host);
216  result.append("\n"+gammalib::parformat("Hub port")+m_hub_port);
217  result.append("\n"+gammalib::parformat("Hub path")+m_hub_path);
218  result.append("\n"+gammalib::parformat("SAMP protocol version"));
219  result.append(m_version);
220 
221  } // endif: chatter was not silent
222 
223  // Return result
224  return result;
225 }
226 
227 
228 /*==========================================================================
229  = =
230  = Private methods =
231  = =
232  ==========================================================================*/
233 
234 /***********************************************************************//**
235  * @brief Initialise class members
236  ***************************************************************************/
238 {
239  // Initialise members
240  m_secret = random_string(15);
241  m_hub_host = "127.0.0.1";
242  m_hub_port = "2526";
243  m_hub_path = "xmlrpc";
244  m_version = "1.3";
245  m_hub_id = "gammalib_hub";
246  m_socket = -1; // Signals no socket
247  m_shutdown = false;
248  m_clients.clear();
249 
250  // Return
251  return;
252 }
253 
254 
255 /***********************************************************************//**
256  * @brief Copy class members
257  *
258  * @param[in] hub VO hub.
259  ***************************************************************************/
260 void GVOHub::copy_members(const GVOHub& hub)
261 {
262  // Copy members
263  m_secret = hub.m_secret;
264  m_hub_host = hub.m_hub_host;
265  m_hub_port = hub.m_hub_port;
266  m_hub_path = hub.m_hub_path;
267  m_version = hub.m_version;
268  m_hub_id = hub.m_hub_id;
269  m_socket = hub.m_socket;
270  m_shutdown = hub.m_shutdown;
271  m_clients = hub.m_clients;
272 
273  // Return
274  return;
275 }
276 
277 
278 /***********************************************************************//**
279  * @brief Delete class members
280  ***************************************************************************/
282 {
283  // Close sockets
284  if (m_socket != -1) {
285  close(m_socket);
286  m_socket = -1;
287  }
288 
289  // Remove lockfile
291 
292  // Return
293  return;
294 }
295 
296 
297 /***********************************************************************//**
298  * @brief Starts the SAMP hub socket and listens on it
299  *
300  * @exception GException::runtime_error
301  * Problem with creating of or listening on socket
302  *
303  * This is the main Hub event loop.
304  ***************************************************************************/
306 {
307  // Get socket
308  m_socket = get_socket();
309 
310  // Create SAMP file
312 
313  // Start listening for the clients: 5 requests simultaneously pending
314  // at maximum
315  if (listen(m_socket, 5) < 0) {
316  std::string msg = "Unable to start listening on Hub socket. Errno="+
317  gammalib::str(errno);
319  }
320 
321  // ...
322  struct sockaddr_in cli_addr;
323  socklen_t clilen = sizeof(cli_addr);
324 
325  // Main event handling loop
326  while (true) {
327 
328  // Accept connection from the client
329  int socket = accept(m_socket, (struct sockaddr *)&cli_addr, &clilen);
330  if (socket < 0) {
331  std::string msg = "Client connection to socket not accepted.";
333  }
334 
335  // Handle request
336  handle_request(socket);
337 
338  // Close socket
339  close(socket);
340 
341  // If we have received a shutdown request then exit the event
342  // loop
343  if (m_shutdown) {
344  break;
345  }
346 
347  } // endwhile: main event loop
348 
349  // Close socket
350  close(m_socket);
351  m_socket = -1;
352 
353  // Delete SAMP file
355 
356  // Return
357  return;
358 }
359 
360 
361 /***********************************************************************//**
362  * @brief Reads the client message and runs appropriate function
363  *
364  * @param[in] sock Socket to client.
365  ***************************************************************************/
366 void GVOHub::handle_request(const socklen_t& sock)
367 {
368  // Header
369  #if defined(G_CONSOLE_DUMP)
370  std::cout << "GVOHub::handle_request" << std::endl;
371  #endif
372 
373  // Initialize buffer
374  char buffer[1001];
375 
376  // Initialise message
377  std::string message = "";
378 
379  // Read from socket until nothing is received anymore.
380  int timeout = 2000; // Initial timeout is 2 sec
381  int n = 0;
382  do {
383  n = gammalib::recv(sock, buffer, 1000, 0, timeout);
384  if (n > 0) {
385  buffer[n] = '\0';
386  message.append(std::string(buffer));
387  }
388  timeout = 10; // The timeout now is 0.01 sec
389  } while (n > 0);
390 
391  // Dump the buffer
392  #if defined(G_SHOW_MESSAGE)
393  std::cout << std::endl;
394  std::cout << "GVOHub has received the following message:" << std::endl;
395  std::cout << "==========================================" << std::endl;
396  std::cout << message << std::endl;
397  #endif
398 
399  // Extract response into an XML object
400  GXml xml;
401  size_t start = message.find("<?xml");
402  if (start != std::string::npos) {
403  xml = GXml(message.substr(start, std::string::npos));
404  }
405 
406  // Get methodName value
407  std::string method_called;
408  const GXmlNode* node = xml.element("methodCall > methodName");
409  if (node != NULL) {
410  const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
411  if (text != NULL) {
412  method_called = text->text();
413  }
414  }
415 
416  // Dump the method that is called
417  #if defined(G_CONSOLE_DUMP)
418  std::cout << "GVOHub has received the message type \"";
419  std::cout << method_called << "\"" << std::endl;
420  #endif
421 
422  // Dispatch according to method
423  if (method_called.compare("samp.hub.ping") == 0) {
424  request_ping(sock);
425  }
426  else if (method_called.compare("samp.hub.register") == 0) {
427  request_register(xml, sock);
428  }
429  else if (method_called.compare("samp.hub.unregister") == 0) {
430  request_unregister(xml, sock);
431  }
432  else if (method_called.compare("samp.hub.declareMetadata") == 0) {
433  request_declare_metadata(xml, sock);
434  }
435  else if (method_called.compare("samp.hub.declareSubscriptions") == 0) {
437  }
438  else if (method_called.compare("samp.hub.setXmlrpcCallback") == 0) {
439  request_set_xml_rpc_callback(xml, sock);
440  }
441  else if (method_called.compare("samp.hub.getSubscriptions") == 0) {
442  request_get_subscriptions(xml, sock);
443  }
444  else if (method_called.compare("samp.hub.getRegisteredClients") == 0) {
446  }
447  else if (method_called.compare("samp.hub.getSubscribedClients") == 0) {
449  }
450  else if (method_called.compare("samp.hub.getMetadata") == 0) {
451  request_get_metadata(xml, sock);
452  }
453  else if (method_called.compare("samp.hub.notify") == 0) {
454  request_ping(sock);
455  }
456  else if (method_called.compare("samp.hub.notifyAll") == 0) {
457  request_notify_all(xml, sock);
458  }
459  else if (method_called.compare("samp.hub.call") == 0) {
460  request_ping(sock);
461  }
462  else if (method_called.compare("samp.hub.callAll") == 0) {
463  request_ping(sock);
464  }
465  else if (method_called.compare("samp.hub.callAndWait") == 0) {
466  request_ping(sock);
467  }
468  else if (method_called.compare("samp.hub.reply") == 0) {
469  request_ping(sock);
470  }
471  else if (method_called.compare("samp.hub.shutdown") == 0) {
472  request_shutdown(sock);
473  }
474 
475  // Return
476  return;
477 }
478 
479 
480 /***********************************************************************//**
481  * @brief Handles ping requests
482  *
483  * @param[in] sock Socket.
484  *
485  * Handles all incoming ping requests.
486  ***************************************************************************/
487 void GVOHub::request_ping(const socklen_t& sock)
488 {
489  // Header
490  #if defined(G_CONSOLE_DUMP)
491  std::cout << "GVOHub::request_ping" << std::endl;
492  #endif
493 
494  // Post void message
495  post_samp_void(sock);
496 
497  // Return
498  return;
499 }
500 
501 
502 /***********************************************************************//**
503  * @brief Handles registration requests
504  *
505  * @param[in] xml XML message sent by client.
506  * @param[in] sock Socket.
507  *
508  * Handles all incoming registration requests.
509  ***************************************************************************/
510 void GVOHub::request_register(const GXml& xml, const socklen_t& sock)
511 {
512  // Header
513  #if defined(G_CONSOLE_DUMP)
514  std::cout << "GVOHub::request_register" << std::endl;
515  #endif
516 
517  // Set client reference
518  int counter = 0;
519  std::string reference;
520  do {
521  reference = "c"+gammalib::str(counter);
522  int i = 0;
523  for (; i < m_clients.size(); ++i) {
524  if (m_clients[i].reference == reference) {
525  counter++;
526  break;
527  }
528  }
529  if (i >= m_clients.size()) {
530  break;
531  }
532  } while (true);
533 
534  // Create a new client
535  struct client voclient;
536  voclient.reference = reference;
537  voclient.private_key = random_string(15);
538 
539  // Attached client
540  m_clients.push_back(voclient);
541 
542  // Declare response
543  std::string response = "";
544 
545  // Set response
546  response.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
547  response.append("<methodResponse>\n");
548  response.append("<params>\n");
549  response.append(" <param><value><struct>\n");
550  response.append(" <member>\n");
551  response.append(" <name>samp.private-key</name>\n");
552  response.append(" <value>"+voclient.private_key+"</value>\n");
553  response.append(" </member>\n");
554  response.append(" <member>\n");
555  response.append(" <name>samp.hub-id</name>\n");
556  response.append(" <value>"+m_hub_id+"</value>\n");
557  response.append(" </member>\n");
558  response.append(" <member>\n");
559  response.append(" <name>samp.self-id</name>\n");
560  response.append(" <value>"+voclient.reference+"</value>\n");
561  response.append(" </member>\n");
562  response.append(" <member>\n");
563  response.append(" <name>samp.status</name>\n");
564  response.append(" <value>samp.ok</value>\n");
565  response.append(" </member>\n");
566  response.append(" <member>\n");
567  response.append(" <name>samp.url-translator</name>\n");
568  response.append(" <value>"+hub_url()+"</value>\n");
569  response.append(" </member>\n");
570  response.append(" </struct></value></param>\n");
571  response.append("</params>\n");
572  response.append("</methodResponse>\n");
573 
574  // Post response
575  post_string(response, sock);
576 
577  // Notify all clients about the registering
578  for (int i = 0; i < m_clients.size(); ++i) {
579  for (int j = 0; j < m_clients[i].subscriptions.size(); ++j) {
580  if ("samp.hub.event.register" == m_clients[i].subscriptions[j]) {
581  notify_register(m_clients[i], voclient.reference);
582  break;
583  }
584  }
585  }
586 
587  // Return
588  return;
589 }
590 
591 
592 /***********************************************************************//**
593  * @brief Handles unregistration requests
594  *
595  * @param[in] xml XML message sent by client.
596  * @param[in] sock Socket.
597  *
598  * Handles all incoming unregistration requests.
599  ***************************************************************************/
600 void GVOHub::request_unregister(const GXml& xml, const socklen_t& sock)
601 {
602  // Optionally dump header
603  #if defined(G_CONSOLE_DUMP)
604  std::cout << "GVOHub::request_unregister" << std::endl;
605  #endif
606 
607  // Get client index
608  int i = get_client_index(xml);
609 
610  // Continue only if index is valid
611  if (i != -1) {
612 
613  // Post void message
614  post_samp_void(sock);
615 
616  // Notify all clients about the registering
617  for (int k = 0; k < m_clients.size(); ++k) {
618  if (i != k) {
619  for (int j = 0; j < m_clients[k].subscriptions.size(); ++j) {
620  if ("samp.hub.event.unregister" == m_clients[k].subscriptions[j]) {
621  notify_unregister(m_clients[k], m_clients[i].reference);
622  }
623  }
624  }
625  }
626 
627  // Remove client
628  m_clients.erase(m_clients.begin()+i);
629 
630  } // endif: valid client found
631 
632  // Signal if the client was unknown
633  #if defined(G_CONSOLE_ERRORS)
634  else {
635  std::cout << "*** ERROR: GVOHub::request_unregister: ";
636  std::cout << "Unable to find client \"" << get_client_key(xml);
637  std::cout << "\"" << std::endl;
638  }
639  #endif
640 
641  // Return
642  return;
643 }
644 
645 
646 /***********************************************************************//**
647  * @brief Handles metadata declaration requests
648  *
649  * @param[in] xml XML message sent by client.
650  * @param[in] sock Socket.
651  *
652  * Handles all incoming metadata declaration requests.
653  ***************************************************************************/
654 void GVOHub::request_declare_metadata(const GXml& xml, const socklen_t& sock)
655 {
656  // Header
657  #if defined(G_CONSOLE_DUMP)
658  std::cout << "GVOHub::request_declare_metadata" << std::endl;
659  #endif
660 
661  // Get client index
662  int i = get_client_index(xml);
663 
664  // Continue only if index is valid
665  if (i != -1) {
666 
667  // Get node
668  const GXmlNode* node = xml.element("methodCall > params > param[1] > value > struct");
669 
670  // Store metadata
671  m_clients[i].name = get_response_value(node, "samp.name");;
672  m_clients[i].description = get_response_value(node, "samp.description.text");
673  m_clients[i].icon = get_response_value(node, "samp.icon.url");
674  m_clients[i].documentation = get_response_value(node, "samp.documentation.url");
675  m_clients[i].affiliation = get_response_value(node, "author.affiliation");
676  m_clients[i].email = get_response_value(node, "author.email");
677  m_clients[i].author_name = get_response_value(node, "author.name");
678  m_clients[i].homepage = get_response_value(node, "home.page");
679 
680  // Post void message
681  post_samp_void(sock);
682 
683  // Notify all clients about the registering
684  for (int k = 0; k < m_clients.size(); ++k) {
685  if (i != k) {
686  for (int j = 0; j < m_clients[k].subscriptions.size(); ++j) {
687  if ("samp.hub.event.metadata" == m_clients[k].subscriptions[j]) {
688  notify_metadata(m_clients[k], m_clients[i].reference);
689  }
690  }
691  }
692  }
693 
694  } // endif: client found
695 
696  // Signal if the client was unknown
697  #if defined(G_CONSOLE_ERRORS)
698  else {
699  std::cout << "*** ERROR: GVOHub::request_declare_metadata: ";
700  std::cout << "Unable to find client \"" << get_client_key(xml);
701  std::cout << "\"" << std::endl;
702  }
703  #endif
704 
705  // Return
706  return;
707 }
708 
709 
710 /***********************************************************************//**
711  * @brief Handles subscriptions declaration requests
712  *
713  * @param[in] xml XML message sent by client.
714  * @param[in] sock Socket.
715  *
716  * Handles all incoming subscription declaration requests.
717  ***************************************************************************/
718 void GVOHub::request_declare_subscriptions(const GXml& xml,const socklen_t& sock)
719 {
720  // Header
721  #if defined(G_CONSOLE_DUMP)
722  std::cout << "GVOHub::request_declare_subscriptions" << std::endl;
723  #endif
724 
725  // Get client index
726  int i = get_client_index(xml);
727 
728  // Continue only if index is valid
729  if (i != -1) {
730 
731  // Get subscriptions
732  std::vector<std::string> subscriptions = get_subscriptions(xml);
733 
734  // Store subscriptions
735  for (int k = 0; k < subscriptions.size(); ++k) {
736  m_clients[i].subscriptions.push_back(subscriptions[k]);
737  }
738 
739  // Post SAMP ok
740  post_samp_ok(sock);
741 
742  } // endif: valid client found
743 
744  // Signal if the client was unknown
745  #if defined(G_CONSOLE_ERRORS)
746  else {
747  std::cout << "*** ERROR: GVOHub::request_declare_subscriptions: ";
748  std::cout << "Unable to find client \"" << get_client_key(xml);
749  std::cout << "\"" << std::endl;
750  }
751  #endif
752 
753  // Return
754  return;
755 }
756 
757 
758 /***********************************************************************//**
759  * @brief Handles XML-RPC callback setting requests
760  *
761  * @param[in] xml XML message sent by client.
762  * @param[in] sock Socket.
763  *
764  * Handles all incoming XML-RPC callback setting requests.
765  ***************************************************************************/
767  const socklen_t& sock)
768 {
769  // Header
770  #if defined(G_CONSOLE_DUMP)
771  std::cout << "GVOHub::request_set_xml_rpc_callback" << std::endl;
772  #endif
773 
774  // Get client index
775  int i = get_client_index(xml);
776 
777  // Continue only if index is valid
778  if (i != -1) {
779 
780  // Set callback URL
781  m_clients[i].url = get_callback_url(xml);
782 
783  // Post SAMP ok
784  post_samp_ok(sock);
785 
786  } // endif: client found
787 
788  // Signal if the client was unknown
789  #if defined(G_CONSOLE_ERRORS)
790  else {
791  std::cout << "*** ERROR: GVOHub::request_set_xml_rpc_callback: ";
792  std::cout << "Unable to find client \"" << get_client_key(xml);
793  std::cout << "\"" << std::endl;
794  }
795  #endif
796 
797  // Return
798  return;
799 }
800 
801 
802 /***********************************************************************//**
803  * @brief Handles subscriptions getting requests
804  *
805  * @param[in] xml XML message sent by client.
806  * @param[in] sock Socket.
807  *
808  * Handles all incoming subscriptions getting requests.
809  ***************************************************************************/
810 void GVOHub::request_get_subscriptions(const GXml& xml, const socklen_t& sock)
811 {
812  // Header
813  #if defined(G_CONSOLE_DUMP)
814  std::cout << "GVOHub::request_get_subscriptions" << std::endl;
815  #endif
816 
817  // Get the client name
818  std::string client_name = get_client_name(xml);
819 
820  // Declare response
821  std::string response = "";
822 
823  // Set response
824  response.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
825  response.append("<methodResponse>\n");
826  response.append("<params>\n");
827  response.append(" <param><value><struct>\n");
828 
829  // If key is "gammalib_hub" then return some special information
830  if (client_name == "gammalib_hub") {
831  // Do nothing
832  }
833 
834  // ... handle all other clients
835  else {
836 
837  // Get client index
838  int i = get_client_index(client_name);
839 
840  // Continue only if index is valid
841  if (i != -1) {
842 
843  // Append all subscriptions
844  for (int k = 0; k < m_clients[i].subscriptions.size(); ++k) {
845  response.append(" <member>\n");
846  response.append(" <name>");
847  response.append(m_clients[i].subscriptions[k]);
848  response.append("</name>\n");
849  response.append(" <value></value>\n");
850  response.append(" </member>\n");
851  }
852 
853  }
854 
855  // Signal if the client was unknown
856  #if defined(G_CONSOLE_ERRORS)
857  else {
858  std::cout << "*** ERROR: GVOHub::request_get_subscriptions: ";
859  std::cout << "Unable to find client \"" << get_client_key(xml);
860  std::cout << "\"" << std::endl;
861  }
862  #endif
863 
864  }
865 
866  // Finish response
867  response.append(" </struct></value></param>\n");
868  response.append("</params>\n");
869  response.append("</methodResponse>\n");
870 
871  // Post response
872  post_string(response, sock);
873 
874  // Return
875  return;
876 }
877 
878 
879 /***********************************************************************//**
880  * @brief Handles registered client information requests
881  *
882  * @param[in] xml XML message sent by client.
883  * @param[in] sock Socket.
884  *
885  * Handles all incoming registered client information requests.
886  ***************************************************************************/
887 void GVOHub::request_get_registered_clients(const GXml& xml, const socklen_t& sock)
888 {
889  // Header
890  #if defined(G_CONSOLE_DUMP)
891  std::cout << "GVOHub::request_get_registered_clients" << std::endl;
892  #endif
893 
894  // Get client key
895  std::string key = get_client_key(xml);
896 
897  // Declare message
898  std::string msg = "";
899 
900  // Set response
901  msg.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
902  msg.append("<methodResponse>\n");
903  msg.append("<params>\n");
904  msg.append(" <param><value><array><data>\n");
905  msg.append(" <value>gammalib_hub</value>\n");
906 
907  // Loop over all clients. Do not send back current client's registration
908  for (int i = 0; i < m_clients.size(); ++i) {
909  if (m_clients[i].private_key != key) {
910  msg.append(" <value>");
911  msg.append(m_clients[i].reference);
912  msg.append("</value>\n");
913  }
914  }
915 
916  // Finish response
917  msg.append(" </data></array></value></param>\n");
918  msg.append("</params>\n");
919  msg.append("</methodResponse>\n");
920 
921  // Post response
922  post_string(msg, sock);
923 
924  // Return
925  return;
926 }
927 
928 
929 /***********************************************************************//**
930  * @brief Handles subscribed client information requests
931  *
932  * @param[in] xml XML message sent by client.
933  * @param[in] sock Socket.
934  *
935  * Handles all incoming subscribed client information requests.
936  ***************************************************************************/
937 void GVOHub::request_get_subscribed_clients(const GXml& xml, const socklen_t& sock)
938 {
939  // Header
940  #if defined(G_CONSOLE_DUMP)
941  std::cout << "GVOHub::request_get_subscribed_clients" << std::endl;
942  #endif
943 
944  // Declare message
945  std::string msg = "";
946 
947  msg.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
948  msg.append("<methodResponse>\n");
949  msg.append("<params>\n");
950  msg.append(" <param><value><struct>\n");
951  msg.append(" <member>\n");
952  msg.append(" <name>c0</name>\n");
953  msg.append(" <value><struct></struct></value>\n");
954  msg.append(" </member>\n");
955  msg.append(" <member>\n");
956  msg.append(" <name>gammalib_hub</name>\n");
957  msg.append(" <value><struct></struct></value>\n");
958  msg.append(" </member>\n");
959  msg.append(" </struct></value></param>\n");
960  msg.append("</params>\n");
961  msg.append("</methodResponse>");
962 
963  // Post response
964  post_string(msg, sock);
965 
966  // Return
967  return;
968 }
969 
970 
971 /***********************************************************************//**
972  * @brief Handles a metadata requests
973  *
974  * @param[in] xml XML message sent by client.
975  * @param[in] sock Socket.
976  *
977  * Handles all metadata requests.
978  ***************************************************************************/
979 void GVOHub::request_get_metadata(const GXml& xml, const socklen_t& sock)
980 {
981  // Header
982  #if defined(G_CONSOLE_DUMP)
983  std::cout << "GVOHub::request_get_metadata" << std::endl;
984  #endif
985 
986  // Get the client name
987  std::string client_name = get_client_name(xml);
988 
989  // Declare response
990  std::string response = "";
991 
992  // Set response
993  response.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
994  response.append("<methodResponse>\n");
995  response.append("<params>\n");
996  response.append(" <param><value><struct>\n");
997  response.append(" <member>\n");
998  response.append(" <name>samp.status</name>\n");
999  response.append(" <value>samp.ok</value>\n");
1000  response.append(" </member>\n");
1001 
1002  // If key is "gammalib_hub" then return some special information
1003  if (client_name == "gammalib_hub") {
1004  response.append(" <member>\n");
1005  response.append(" <name>samp.name</name>\n");
1006  response.append(" <value>gammalib_hub</value>\n");
1007  response.append(" </member>\n");
1008  response.append(" <member>\n");
1009  response.append(" <name>samp.description.text</name>\n");
1010  response.append(" <value>GammaLib VO Hub</value>\n");
1011  response.append(" </member>\n");
1012  response.append(" <member>\n");
1013  response.append(" <name>samp.icon.url</name>\n");
1014  response.append(" <value>http://a.fsdn.com/allura/p/gammalib/icon</value>\n");
1015  response.append(" </member>\n");
1016  response.append(" <member>\n");
1017  response.append(" <name>samp.documentation.url</name>\n");
1018  response.append(" <value>http://cta.irap.omp.eu/gammalib/user_manual/modules/vo.html</value>\n");
1019  response.append(" </member>\n");
1020  response.append(" <member>\n");
1021  response.append(" <name>author.affiliation</name>\n");
1022  response.append(" <value>IRAP, Toulouse, France</value>\n");
1023  response.append(" </member>\n");
1024  response.append(" <member>\n");
1025  response.append(" <name>author.email</name>\n");
1026  response.append(" <value>jurgen.knodlseder@irap.omp.eu</value>\n");
1027  response.append(" </member>\n");
1028  response.append(" <member>\n");
1029  response.append(" <name>author.name</name>\n");
1030  response.append(" <value>J. Knoedlseder, T. Louge</value>\n");
1031  response.append(" </member>\n");
1032  response.append(" <member>\n");
1033  response.append(" <name>home.page</name>\n");
1034  response.append(" <value>http://cta.irap.omp.eu/gammalib/</value>\n");
1035  response.append(" </member>\n");
1036  }
1037 
1038  // ... otherwise get the index
1039  else {
1040 
1041  // Get client index
1042  int i = get_client_index(client_name);
1043 
1044  // Continue only if index is valid
1045  if (i != -1) {
1046 
1047  // Append response
1048  response.append(" <member>\n");
1049  response.append(" <name>samp.name</name>\n");
1050  response.append(" <value>"+m_clients[i].name+"</value>\n");
1051  response.append(" </member>\n");
1052  response.append(" <member>\n");
1053  response.append(" <name>samp.description.text</name>\n");
1054  response.append(" <value>"+m_clients[i].description+"</value>\n");
1055  response.append(" </member>\n");
1056  response.append(" <member>\n");
1057  response.append(" <name>samp.icon.url</name>\n");
1058  response.append(" <value>"+m_clients[i].icon+"</value>\n");
1059  response.append(" </member>\n");
1060  response.append(" <member>\n");
1061  response.append(" <name>samp.documentation.url</name>\n");
1062  response.append(" <value>"+m_clients[i].documentation+"</value>\n");
1063  response.append(" </member>\n");
1064  response.append(" <member>\n");
1065  response.append(" <name>author.affiliation</name>\n");
1066  response.append(" <value>"+m_clients[i].affiliation+"</value>\n");
1067  response.append(" </member>\n");
1068  response.append(" <member>\n");
1069  response.append(" <name>author.email</name>\n");
1070  response.append(" <value>"+m_clients[i].email+"</value>\n");
1071  response.append(" </member>\n");
1072  response.append(" <member>\n");
1073  response.append(" <name>author.name</name>\n");
1074  response.append(" <value>"+m_clients[i].author_name+"</value>\n");
1075  response.append(" </member>\n");
1076  response.append(" <member>\n");
1077  response.append(" <name>home.page</name>\n");
1078  response.append(" <value>"+m_clients[i].homepage+"</value>\n");
1079  response.append(" </member>\n");
1080 
1081  } // endif: index was valid
1082 
1083  // Signal if the client was unknown
1084  #if defined(G_CONSOLE_ERRORS)
1085  else {
1086  std::cout << "*** ERROR: GVOHub::request_get_metadata: ";
1087  std::cout << "Unable to find client \"" << get_client_key(xml);
1088  std::cout << "\"" << std::endl;
1089  }
1090  #endif
1091 
1092  } // endelse: client was not the hub
1093 
1094  // Finish response
1095  response.append(" </struct></value></param>\n");
1096  response.append("</params>\n");
1097  response.append("</methodResponse>\n");
1098 
1099  // Post response
1100  post_string(response, sock);
1101 
1102  // Return
1103  return;
1104 }
1105 
1106 
1107 /***********************************************************************//**
1108  * @brief Handle request to notify all clients
1109  *
1110  * @param[in] xml XML message sent by client.
1111  * @param[in] sock Socket.
1112  *
1113  * Handles requests to notify all clients. The method will loop over all
1114  * clients to check the subscriptions of each client, and send a notification
1115  * to all clients that are subscribed to the requested message type.
1116  ***************************************************************************/
1117 void GVOHub::request_notify_all(const GXml& xml, const socklen_t& sock)
1118 {
1119  // Header
1120  #if defined(G_CONSOLE_DUMP)
1121  std::cout << "GVOHub::request_notify_all entrance" << std::endl;
1122  #endif
1123 
1124  // Get message type
1125  std::string mtype = get_mtype(xml);
1126 
1127  #if defined(G_CONSOLE_DUMP)
1128  std::cout << "mtype:"+mtype << std::endl;
1129  #endif
1130 
1131  // Post void message
1132  post_samp_void(sock);
1133 
1134  // Loop over all clients
1135  for (int i = 0; i < m_clients.size(); ++i) {
1136 
1137  // Loop over all subscriptions
1138  for (int j = 0; j < m_clients[i].subscriptions.size(); ++j) {
1139 
1140  // Continue only if message type matches client's subscription
1141  if (mtype == m_clients[i].subscriptions[j]) {
1142 
1143  // Image loading?
1144  if (mtype == "image.load.fits") {
1145  notify_image_load(m_clients[i], xml);
1146  }
1147 
1148  // ... or VO table loading?
1149  else if (mtype == "table.load.votable") {
1150  notify_table_load(m_clients[i], xml);
1151  }
1152 
1153  } // endif: message type matched client subscription
1154 
1155  } // endfor: looped over all message types
1156 
1157  } // endfor: looped over all clients
1158 
1159  // Return
1160  return;
1161 
1162 }
1163 
1164 
1165 /***********************************************************************//**
1166  * @brief Handles Hub shutdown requests
1167  *
1168  * @param[in] sock Socket.
1169  *
1170  * Handles all incoming Hub shutdown requests.
1171  ***************************************************************************/
1172 void GVOHub::request_shutdown(const socklen_t& sock)
1173 {
1174  // Header
1175  #if defined(G_CONSOLE_DUMP)
1176  std::cout << "GVOHub::request_shutdown" << std::endl;
1177  #endif
1178 
1179  // Set shutdown flag
1180  m_shutdown = true;
1181 
1182  // Post SAMP ok
1183  post_samp_ok(sock);
1184 
1185  // Return
1186  return;
1187 }
1188 
1189 
1190 /***********************************************************************//**
1191  * @brief Extract client key from XML request
1192  *
1193  * @param[in] xml XML message sent by client.
1194  *
1195  * Extracts the clients key from the XML request.
1196  ***************************************************************************/
1197 std::string GVOHub::get_client_key(const GXml& xml) const
1198 {
1199  // Header
1200  #if defined(G_CONSOLE_DUMP)
1201  std::cout << "GVOHub::get_client_key" << std::endl;
1202  #endif
1203 
1204  // Initialise response
1205  std::string client_key = "";
1206 
1207  // Get the client's private key
1208  const GXmlNode* node = xml.element("methodCall > params > param > value");
1209  if (node != NULL) {
1210  const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
1211  if (text != NULL) {
1212  client_key = text->text();
1213  }
1214  }
1215 
1216  // Return key
1217  return client_key;
1218 }
1219 
1220 
1221 /***********************************************************************//**
1222  * @brief Extract client index in shared memory from XML request
1223  *
1224  * @param[in] xml XML message sent by client.
1225  * @return Client index (-1 if not found).
1226  *
1227  * Extracts the client index from the XML request. The method returns -1 if
1228  * no client was found.
1229  ***************************************************************************/
1230 int GVOHub::get_client_index(const GXml& xml) const
1231 {
1232  // Header
1233  #if defined(G_CONSOLE_DUMP)
1234  std::cout << "GVOHub::get_client_index" << std::endl;
1235  #endif
1236 
1237  // Initialise index
1238  int index = -1;
1239 
1240  // Get the client's private key
1241  std::string key = get_client_key(xml);
1242 
1243  // Continue only if string is not empty
1244  if (!key.empty()) {
1245 
1246  // Searches for key in clients
1247  for (int i = 0; i < m_clients.size(); ++i) {
1248  if (m_clients[i].private_key == key) {
1249  index = i;
1250  break;
1251  }
1252  }
1253 
1254  } // endif: key was not empty
1255 
1256  // Return index
1257  return index;
1258 }
1259 
1260 
1261 /***********************************************************************//**
1262  * @brief Extract client index in shared memory from XML request
1263  *
1264  * @param[in] reference Client reference.
1265  * @return Client index (-1 if not found).
1266  *
1267  * Extracts the client index from the client reference. The method returns -1
1268  * if no client was found.
1269  ***************************************************************************/
1270 int GVOHub::get_client_index(const std::string& reference) const
1271 {
1272  // Header
1273  #if defined(G_CONSOLE_DUMP)
1274  std::cout << "GVOHub::get_client_index" << std::endl;
1275  #endif
1276 
1277  // Initialise index
1278  int index = -1;
1279 
1280  // Search for index
1281  for (int i = 0; i < m_clients.size(); ++i) {
1282  if (m_clients[i].reference == reference) {
1283  index = i;
1284  break;
1285  }
1286  }
1287 
1288  // Return index
1289  return index;
1290 }
1291 
1292 
1293 /***********************************************************************//**
1294  * @brief Returns value for a named parameter
1295  *
1296  * @param[in] node XML node containing the response values.
1297  * @param[in] name Parameter name.
1298  * @return Parameter value.
1299  *
1300  * Returns the @p value for the parameter @p name in a list of @p member
1301  * XML nodes with the structure
1302  *
1303  * <member>
1304  * <name>name</name>
1305  * <value>value</value>
1306  * </member>
1307  *
1308  * If the specified parameter @p name was not found, or the the XML @p node
1309  * is NULL, an empty string is returned.
1310  ***************************************************************************/
1311 std::string GVOHub::get_response_value(const GXmlNode* node,
1312  const std::string& name) const
1313 {
1314  // Declare empty value
1315  std::string value = "";
1316 
1317  // Search for parameter name, and if found, return its value
1318  if (node != NULL) {
1319  #if defined(G_CONSOLE_DUMP)
1320  std::cout << "GVOHub::get_response_value parsing non null node" << std::endl;
1321  #endif
1322  int num = node->elements("member");
1323  for (int i = 0; i < num; ++i) {
1324  const GXmlNode* member = node->element("member", i);
1325  std::string one_name;
1326  std::string one_value;
1327  gammalib::xml_get_name_value_pair(member, one_name, one_value);
1328  #if defined(G_CONSOLE_DUMP)
1329  std::cout << "GVOHub::get_response_value parsing "+one_name+ " " + one_value << std::endl;
1330  #endif
1331  if (one_name == name) {
1332  value = one_value;
1333  break;
1334  }
1335  }
1336 
1337  } else {
1338  #if defined(G_CONSOLE_DUMP)
1339  std::cout << "GVOHub::get_response_value parsing NULL node" << std::endl;
1340  #endif
1341  }
1342  // Return value
1343  return value;
1344 }
1345 
1346 
1347 /***********************************************************************//**
1348  * @brief Returns subscriptions from XML document
1349  *
1350  * @param[in] xml client query XML document.
1351  * @return List of subscriptions.
1352  ***************************************************************************/
1353 std::vector<std::string> GVOHub::get_subscriptions(const GXml& xml) const
1354 {
1355  // Declare subscriptions
1356  std::vector<std::string> subscriptions;
1357 
1358  // Get the client's private key
1359  const GXmlNode* node = xml.element("methodCall > params > param[1] > "
1360  "value > struct");
1361  if (node != NULL) {
1362  int num = node->elements("member");
1363  for (int i = 0; i < num; ++i) {
1364  const GXmlNode* member = node->element("member", i);
1365  if (member != NULL) {
1366  const GXmlNode* name = member->element("name", 0);
1367  if (name != NULL) {
1368  const GXmlText* text = static_cast<const GXmlText*>((*name)[0]);
1369  if (text != NULL) {
1370  subscriptions.push_back(text->text());
1371  }
1372  }
1373  }
1374  }
1375  }
1376 
1377  // Return subscriptions
1378  return subscriptions;
1379 }
1380 
1381 
1382 /***********************************************************************//**
1383  * @brief Returns callback URL of client
1384  *
1385  * @param[in] xml client query XML document.
1386  * @return Callback URL of client.
1387  ***************************************************************************/
1388 std::string GVOHub::get_callback_url(const GXml& xml) const
1389 {
1390  // Declare URL
1391  std::string url;
1392 
1393  // Get the client's private key
1394  const GXmlNode* node = xml.element("methodCall > params > param[1] > "
1395  "value");
1396  if (node != NULL) {
1397  const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
1398  if (text != NULL) {
1399  url.append(text->text());
1400  }
1401  }
1402 
1403  // Return URL
1404  return url;
1405 }
1406 
1407 
1408 /***********************************************************************//**
1409  * @brief Returns SAMP Hub lockfile URL
1410  *
1411  * @return SAMP Hub lockfile URL (empty if no lockfile was found).
1412  *
1413  * Implements IVOA standard REC-SAMP-1.3-20120411.
1414  ***************************************************************************/
1415 std::string GVOHub::get_hub_lockfile(void) const
1416 {
1417  // Initialise result
1418  std::string url = "";
1419 
1420  // Check for existence of the SAMP_HUB environment variable first
1421  char* hub_ptr = std::getenv("SAMP_HUB");
1422  if (hub_ptr != NULL) {
1423 
1424  // Check for mandatory std-lockurl: prefix (no other prefixe is
1425  // supported so far)
1426  std::string lockurl = std::string(hub_ptr);
1427  if (lockurl.compare(0, 12, "std-lockurl:") == 0) {
1428 
1429  // Extract URL
1430  url = lockurl.substr(12, std::string::npos);
1431 
1432  } // endif: std-lockurl: prefix found
1433 
1434  }
1435 
1436  // ... otherwise the lockfile should be $HOME/.samp
1437  else {
1438 
1439  // Get user's HOME directory path as the prefix of the full
1440  // path. If the HOME environment variable is not set we
1441  // expect that .samp is in the local directory. This is non
1442  // standard, but prevents for creating an exception here.
1443  std::string prefix = "";
1444  char* home_ptr = std::getenv("HOME");
1445  if (home_ptr != NULL) {
1446  prefix = std::string(home_ptr) + "/";
1447  }
1448 
1449  // Set filename
1450  url = prefix + ".samp";
1451 
1452  } // endelse: no SAMP_HUB environment variable found
1453 
1454  // Return URL
1455  return url;
1456 }
1457 
1458 
1459 /***********************************************************************//**
1460  * @brief Create the lockfile
1461  *
1462  * Creates the SAMP lockfile and fill it with information. Implements IVOA
1463  * standard REC-SAMP-1.3-20120411.
1464  ***************************************************************************/
1466 {
1467  // Get lockfile URL
1468  std::string lockurl = get_hub_lockfile();
1469 
1470  // Open SAMP lockfile. Continue only if opening was successful
1471  FILE* fptr = fopen(lockurl.c_str(), "w");
1472 
1473  // Successful?
1474  if (fptr != NULL) {
1475 
1476  // Write lockfile
1477  fprintf(fptr, "# SAMP lockfile\n");
1478  fprintf(fptr, "# Required keys:\n");
1479  fprintf(fptr, "samp.secret=%s\n", m_secret.c_str());
1480  fprintf(fptr, "samp.hub.xmlrpc.url=%s\n", hub_url().c_str());
1481  fprintf(fptr, "samp.profile.version=%s\n", m_version.c_str());
1482  fprintf(fptr, "# Info stored by hub for some private reason:\n");
1483  fprintf(fptr, "gammalib.hubid=%s\n", m_hub_id.c_str());
1484 
1485  // Close lockfile
1486  fclose(fptr);
1487 
1488  }
1489 
1490  // Return
1491  return;
1492 }
1493 
1494 
1495 /***********************************************************************//**
1496  * @brief Delete the lockfile
1497  *
1498  * Deletes the SAMP lockfile on disk.
1499  ***************************************************************************/
1501 {
1502  // Get lockfile URL
1503  std::string lockurl = get_hub_lockfile();
1504 
1505  // Delete lockfile
1506  std::remove(lockurl.c_str());
1507 
1508  // Return
1509  return;
1510 }
1511 
1512 
1513 /***********************************************************************//**
1514  * @brief Get Hub socket
1515  *
1516  * @return Hub socket (-1 if no socket was found).
1517  *
1518  * Returns Hub socket. Starting from an initial port of 2526 the method
1519  * searches for the next free port and binds it to a socket.
1520  ***************************************************************************/
1522 {
1523  // Initialise socket, port and socket address structure
1524  int sock = -1;
1525  int port = 2526;
1526  struct sockaddr_in serv_addr;
1527 
1528  // Loop over 100 ports at most
1529  for (int i = 0; i < 100; ++i) {
1530 
1531  // Clean TCP/IP structure
1532  std::memset(&serv_addr, 0, sizeof(serv_addr));
1533 
1534  // Set TCP/IP structure
1535  serv_addr.sin_family = AF_INET;
1536  serv_addr.sin_addr.s_addr = inet_addr(m_hub_host.c_str());
1537  serv_addr.sin_port = htons(port);
1538 
1539  // Create Hub socket
1540  sock = socket(AF_INET, SOCK_STREAM, 0);
1541 
1542  // Creation of hub main socket
1543  if (sock < 0) {
1544  std::string msg = "Unable to create Hub socket. Errno="+
1545  gammalib::str(errno);
1547  }
1548 
1549  // Now bind socket to the address and port
1550  if (bind(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
1551  if (errno == EADDRINUSE) {
1552  port++;
1553  close(sock);
1554  }
1555  else {
1556  std::string msg = "Unable to bind Hub socket to address "+
1557  m_hub_host+":"+gammalib::str(port)+
1558  ". Errno="+gammalib::str(errno);
1560  }
1561  }
1562  else {
1563  break;
1564  }
1565 
1566  } // endfor: looped over ports
1567 
1568  // Store port as string
1569  m_hub_port = gammalib::str(port);
1570 
1571  // Return socket
1572  return sock;
1573 }
1574 
1575 
1576 /***********************************************************************//**
1577  * @brief Post string content to client
1578  *
1579  * @param[in] content String content to post.
1580  * @param[in] sock Socket.
1581  *
1582  * Posts the content of a string to a client.
1583  ***************************************************************************/
1584 void GVOHub::post_string(const std::string& content, const socklen_t& sock) const
1585 {
1586  // Continue only if socket is valid
1587  if (sock != -1) {
1588 
1589  // Determine content length
1590  int length = content.length();
1591 
1592  // Set prefix (note that the response has no POST!)
1593  std::string prefix = "HTTP/1.1 200 OK\n"
1594  "Connection: close\n"
1595  "Content-Type: text/xml\n"
1596  "Content-Length: "+gammalib::str(length)+"\n\n";
1597 
1598 
1599  // Build post string
1600  std::string post = prefix + content;
1601 
1602  // Dump message to post
1603  #if defined(G_SHOW_MESSAGE)
1604  std::cout << std::endl;
1605  std::cout << "GVOHub response:" << std::endl;
1606  std::cout << "================" << std::endl;
1607  std::cout << post << std::endl;
1608  #endif
1609 
1610  // Send content to socket
1611  bool done = false;
1612  do {
1613  int length = post.length();
1614  int sent_length = send(sock, post.c_str(), length, 0);
1615  if (sent_length < length) {
1616  post = post.substr(sent_length, std::string::npos);
1617  }
1618  else {
1619  done = true;
1620  }
1621  } while (!done);
1622 
1623  } // endif: socket was valid
1624 
1625  // Return
1626  return;
1627 }
1628 
1629 
1630 /***********************************************************************//**
1631  * @brief Post SAMP ok massage to client
1632  *
1633  * @param[in] sock Socket.
1634  *
1635  * Posts a SAMP OK message to a client.
1636  ***************************************************************************/
1637 void GVOHub::post_samp_ok(const socklen_t& sock) const
1638 {
1639  // Declare response
1640  std::string response = "";
1641 
1642  // Compose response
1643  response.append("<?xml version='1.0' encoding='UTF-8'?>\n");
1644  response.append("<methodResponse>\n");
1645  response.append("<params>\n");
1646  response.append(" <param><value><struct>\n");
1647  response.append(" <member>\n");
1648  response.append(" <name>samp.status</name>\n");
1649  response.append(" <value>samp.ok</value>\n");
1650  response.append(" </member>\n");
1651  response.append(" </struct></value></param>\n");
1652  response.append("</params>\n");
1653  response.append("</methodResponse>\n");
1654 
1655  // Post string
1656  post_string(response, sock);
1657 
1658  // Return
1659  return;
1660 }
1661 
1662 
1663 /***********************************************************************//**
1664  * @brief Post SAMP void massage to client
1665  *
1666  * @param[in] sock Socket.
1667  *
1668  * Posts a void SAMP message to a client. Void messages can typically be
1669  * discared by the client.
1670  ***************************************************************************/
1671 void GVOHub::post_samp_void(const socklen_t& sock) const
1672 {
1673  // Declare response
1674  std::string response = "";
1675 
1676  // Compose response
1677  response.append("<?xml version='1.0' encoding='UTF-8'?>\n");
1678  response.append("<methodResponse>\n");
1679  response.append(" <params>\n");
1680  response.append(" <param>\n");
1681  response.append(" <value/>\n");
1682  response.append(" </param>\n");
1683  response.append(" </params>\n");
1684  response.append("</methodResponse>\n");
1685 
1686  // Post string
1687  post_string(response, sock);
1688 
1689  // Return
1690  return;
1691 }
1692 
1693 
1694 /***********************************************************************//**
1695  * @brief Send notification to client
1696  *
1697  * @param[in] url URL.
1698  * @param[in] notification Notification.
1699  *
1700  * Send a @p notification to a @p url.
1701  ***************************************************************************/
1702 void GVOHub::notify(const std::string& url,
1703  const std::string& notification) const
1704 {
1705  // Initalise socket
1706  int socket = -1;
1707 
1708  // Extract host, port and path from URL
1709  std::string host = "127.0.0.1";
1710  std::string port = "2525";
1711  std::string path = "xmlrpc";
1712  if (url.compare(0, 7, "http://") == 0) {
1713  size_t length;
1714  size_t start = 7;
1715  size_t stop = url.find(":", start);
1716  size_t end = std::string::npos;
1717  if (stop != std::string::npos) {
1718  length = stop - start;
1719  }
1720  else {
1721  length = std::string::npos;
1722  }
1723  host = url.substr(start, length);
1724  if (stop != std::string::npos) {
1725  stop++;
1726  end = url.find("/", stop);
1727  if (end != std::string::npos) {
1728  length = end - stop;
1729  }
1730  else {
1731  length = std::string::npos;
1732  }
1733  port = url.substr(stop, length);
1734  }
1735  if (end != std::string::npos) {
1736  end++;
1737  length = url.length() - end;
1738  path = url.substr(end, length);
1739  }
1740  }
1741 
1742  // Set hints
1743  struct addrinfo hints;
1744  std::memset(&hints, 0, sizeof(hints));
1745  hints.ai_family = AF_INET;
1746  hints.ai_socktype = SOCK_STREAM;
1747 
1748  // Get server information
1749  struct addrinfo* servinfo;
1750  if (getaddrinfo(host.c_str(), port.c_str(), &hints, &servinfo) == 0) {
1751 
1752  // Loop through all the results and connect to the first we can
1753  for (struct addrinfo* ptr = servinfo; ptr != NULL; ptr = ptr->ai_next) {
1754 
1755  // Create socket
1756  socket = ::socket(ptr->ai_family,
1757  ptr->ai_socktype,
1758  ptr->ai_protocol);
1759 
1760  // Connect to socket if socket is valid
1761  if (socket != -1) {
1762  if (::connect(socket,
1763  ptr->ai_addr,
1764  ptr->ai_addrlen) == -1) {
1765  close(socket);
1766  socket = -1;
1767  }
1768  else {
1769  // Socket connection successful, break now
1770  break;
1771  }
1772  }
1773 
1774  } // endfor: looped through all results
1775 
1776  } // endif: server information was valid
1777 
1778  // Continue only if socket is valid
1779  if (socket != -1) {
1780 
1781  // Determine notification length
1782  int length = notification.length();
1783 
1784  // Set prefix
1785  std::string prefix = "POST /"+path+" HTTP/1.0\n"
1786  "Connection: close\n"
1787  "User-Agent: GammaLib\n"
1788  "Content-Type: text/xml\n"
1789  "Content-Length: "+gammalib::str(length)+"\n\n";
1790 
1791  // Build post string
1792  std::string post = prefix + notification;
1793 
1794  // Dump message to post
1795  #if defined(G_SHOW_MESSAGE)
1796  std::cout << std::endl;
1797  std::cout << "GVOHub sends following notification:" << std::endl;
1798  std::cout << "====================================" << std::endl;
1799  std::cout << post << std::endl;
1800  #endif
1801 
1802  // Send content to socket
1803  bool done = false;
1804  do {
1805  int length = post.length() + 1; // +1 for terminating 0
1806  int sent_length = send(socket, post.c_str(), length, 0);
1807  if (sent_length < length) {
1808  post = post.substr(sent_length, std::string::npos);
1809  }
1810  else {
1811  done = true;
1812  }
1813  } while (!done);
1814 
1815  // Close socket
1816  close(socket);
1817 
1818  }
1819 
1820  // Return
1821  return;
1822 }
1823 
1824 
1825 /***********************************************************************//**
1826  * @brief Notify client about another client registering at Hub
1827  *
1828  * @param[in] client Client to notify.
1829  * @param[in] reference Reference to client which registered.
1830  *
1831  * Notify a client about another client that has registered at the Hub. The
1832  * method sends a "samp.hub.event.register" message to the @p client.
1833  ***************************************************************************/
1835  const std::string& reference)
1836 {
1837  // Declare notification
1838  std::string msg = "";
1839 
1840  // Set response for samp.hub.event.register
1841  msg.append("<?xml version=\"1.0\"?>\n");
1842  msg.append("<methodCall>\n");
1843  msg.append("<methodName>samp.client.receiveNotification</methodName>\n");
1844  msg.append("<params>\n");
1845  msg.append(" <param><value>"+client.private_key+"</value></param>\n");
1846  msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
1847  msg.append(" <param><value><struct>\n");
1848  msg.append(" <member>\n");
1849  msg.append(" <name>samp.mtype</name>\n");
1850  msg.append(" <value>samp.hub.event.register</value>\n");
1851  msg.append(" </member>\n");
1852  msg.append(" <member>\n");
1853  msg.append(" <name>samp.params</name>\n");
1854  msg.append(" <value><struct>\n");
1855  msg.append(" <member>\n");
1856  msg.append(" <name>id</name>\n");
1857  msg.append(" <value>"+reference+"</value>\n");
1858  msg.append(" </member>\n");
1859  msg.append(" </struct></value>\n");
1860  msg.append(" </member>\n");
1861  msg.append(" </struct></value></param>\n");
1862  msg.append("</params>\n");
1863  msg.append("</methodCall>\n");
1864 
1865  // Post notification
1866  notify(client.url, msg);
1867 
1868  // Return
1869  return;
1870 }
1871 
1872 
1873 /***********************************************************************//**
1874  * @brief Notify client about another client unregistering at Hub
1875  *
1876  * @param[in] client Client to notify.
1877  * @param[in] reference Reference to client who unregistered.
1878  *
1879  * Notify a client about another client that has unregistered at the Hub. The
1880  * method sends a "samp.hub.event.unregister" message to the @p client.
1881  ***************************************************************************/
1883  const std::string& reference)
1884 {
1885  // Declare notification
1886  std::string msg = "";
1887 
1888  // Set response for samp.hub.event.unregister
1889  msg.append("<?xml version=\"1.0\"?>\n");
1890  msg.append("<methodCall>\n");
1891  msg.append("<methodName>samp.client.receiveNotification</methodName>\n");
1892  msg.append("<params>\n");
1893  msg.append(" <param><value>"+client.private_key+"</value></param>\n");
1894  msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
1895  msg.append(" <param><value><struct>\n");
1896  msg.append(" <member>\n");
1897  msg.append(" <name>samp.mtype</name>\n");
1898  msg.append(" <value>samp.hub.event.unregister</value>\n");
1899  msg.append(" </member>\n");
1900  msg.append(" <member>\n");
1901  msg.append(" <name>samp.params</name>\n");
1902  msg.append(" <value><struct>\n");
1903  msg.append(" <member>\n");
1904  msg.append(" <name>id</name>\n");
1905  msg.append(" <value>"+reference+"</value>\n");
1906  msg.append(" </member>\n");
1907  msg.append(" </struct></value>\n");
1908  msg.append(" </member>\n");
1909  msg.append(" </struct></value></param>\n");
1910  msg.append("</params>\n");
1911  msg.append("</methodCall>\n");
1912 
1913  // Post notification
1914  notify(client.url, msg);
1915 
1916  // Return
1917  return;
1918 }
1919 
1920 
1921 /***********************************************************************//**
1922  * @brief Notify client about the metadata of another client
1923  *
1924  * @param[in] client Client to notify.
1925  * @param[in] reference Reference of client for which metadata should be sent.
1926  *
1927  * Notify a client about another the metadata of another client. The method
1928  * sends a "samp.hub.event.metadata" message to the @p client.
1929  ***************************************************************************/
1931  const std::string& reference)
1932 {
1933  // Get index of reference client
1934  int k;
1935  for (k = 0; k < m_clients.size(); ++k) {
1936  if (m_clients[k].reference == reference) {
1937  break;
1938  }
1939  }
1940 
1941  // Continue only if client index is valid
1942  if (k < m_clients.size()) {
1943 
1944  // Declare notification
1945  std::string msg = "";
1946 
1947  // Set response for samp.hub.event.metadata
1948  msg.append("<?xml version=\"1.0\"?>\n");
1949  msg.append("<methodCall><methodName>samp.client.receiveNotification</methodName>\n");
1950  msg.append("<params>\n");
1951  msg.append(" <param><value>"+client.private_key+"</value></param>\n");
1952  msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
1953  msg.append(" <param><value><struct>\n");
1954  msg.append(" <member>\n");
1955  msg.append(" <name>samp.mtype</name>\n");
1956  msg.append(" <value>samp.hub.event.metadata</value>\n");
1957  msg.append(" </member>\n");
1958  msg.append(" <member>\n");
1959  msg.append(" <name>samp.params</name>\n");
1960  msg.append(" <value><struct>\n");
1961  msg.append(" <member>\n");
1962  msg.append(" <name>id</name>\n");
1963  msg.append(" <value>"+m_clients[k].reference+"</value>\n");
1964  msg.append(" </member>\n");
1965  msg.append(" <member>\n");
1966  msg.append(" <name>metadata</name>\n");
1967  msg.append(" <value><struct>\n");
1968  msg.append(" <member>\n");
1969  msg.append(" <name>samp.name</name>\n");
1970  msg.append(" <value>"+m_clients[k].name+"</value>\n");
1971  msg.append(" </member>\n");
1972  msg.append(" <member>\n");
1973  msg.append(" <name>samp.description.text</name>\n");
1974  msg.append(" <value>"+m_clients[k].description+"</value>\n");
1975  msg.append(" </member>\n");
1976  msg.append(" <member>\n");
1977  msg.append(" <name>samp.icon.url</name>\n");
1978  msg.append(" <value>"+m_clients[k].icon+"</value>\n");
1979  msg.append(" </member>\n");
1980  msg.append(" <member>\n");
1981  msg.append(" <name>samp.documentation.url</name>\n");
1982  msg.append(" <value>"+m_clients[k].documentation+"</value>\n");
1983  msg.append(" </member>\n");
1984  msg.append(" <member>\n");
1985  msg.append(" <name>author.affiliation</name>\n");
1986  msg.append(" <value>"+m_clients[k].affiliation+"</value>\n");
1987  msg.append(" </member>\n");
1988  msg.append(" <member>\n");
1989  msg.append(" <name>author.name</name>\n");
1990  msg.append(" <value>"+m_clients[k].author_name+"</value>\n");
1991  msg.append(" </member>\n");
1992  msg.append(" <member>\n");
1993  msg.append(" <name>author.email</name>\n");
1994  msg.append(" <value>"+m_clients[k].email+"</value>\n");
1995  msg.append(" </member>\n");
1996  msg.append(" <member>\n");
1997  msg.append(" <name>home.page</name>\n");
1998  msg.append(" <value>"+m_clients[k].homepage+"</value>\n");
1999  msg.append(" </member>\n");
2000  msg.append(" </struct></value>\n");
2001  msg.append(" </member>\n");
2002  msg.append(" </struct></value>\n");
2003  msg.append(" </member>\n");
2004  msg.append(" </struct></value></param>\n");
2005  msg.append("</params>\n");
2006  msg.append("</methodCall>\n");
2007 
2008  // Post notification
2009  notify(client.url, msg);
2010 
2011  } // endif: reference client was valid
2012 
2013  // Return
2014  return;
2015 }
2016 
2017 
2018 /***********************************************************************//**
2019  * @brief Notify client about image loading
2020  *
2021  * @param[in] client Client.
2022  * @param[in] xml Message from which image information is extracted.
2023  *
2024  * Notify a client that a FITS image is avialable for loading. The method
2025  * sends a "image.load.fits" message to the @p client. Information about the
2026  * image is extracted from the @p xml document.
2027  ***************************************************************************/
2029  const GXml& xml)
2030 {
2031  // Get client response
2032  const GXmlNode* node = xml.element("methodCall > params > param[1] > "
2033  "value > struct > member > value > "
2034  "struct");
2035 
2036  // Extract image information from client response
2037  std::string name = get_response_value(node, "name");
2038  std::string url = get_response_value(node, "url");
2039  std::string id = get_response_value(node, "image-id");
2040 
2041  // Declare notification
2042  std::string msg = "";
2043 
2044  // Set notification for image.load.fits
2045  msg.append("<?xml version=\"1.0\"?>\n");
2046  msg.append("<methodCall>\n");
2047  msg.append("<methodName>samp.client.receiveNotification</methodName>\n");
2048  msg.append("<params>\n");
2049  msg.append(" <param><value>"+client.private_key+"</value></param>\n");
2050  msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
2051  msg.append(" <param><value><struct>\n");
2052  msg.append(" <member>\n");
2053  msg.append(" <name>samp.mtype</name>\n");
2054  msg.append(" <value>image.load.fits</value>\n");
2055  msg.append(" </member>\n");
2056  msg.append(" <member>\n");
2057  msg.append(" <name>samp.params</name>\n");
2058  msg.append(" <value><struct>\n");
2059  msg.append(" <member>\n");
2060  msg.append(" <name>name</name>\n");
2061  msg.append(" <value>"+name+"</value>\n");
2062  msg.append(" </member>\n");
2063  msg.append(" <member>\n");
2064  msg.append(" <name>image-id</name>\n");
2065  msg.append(" <value>"+id+"</value>\n");
2066  msg.append(" </member>\n");
2067  msg.append(" <member>\n");
2068  msg.append(" <name>url</name>\n");
2069  msg.append(" <value>"+url+"</value>\n");
2070  msg.append(" </member>\n");
2071  msg.append(" </struct></value>\n");
2072  msg.append(" </member>\n");
2073  msg.append(" </struct></value></param>\n");
2074  msg.append("</params>\n");
2075  msg.append("</methodCall>\n");
2076 
2077  // Post notification
2078  notify(client.url, msg);
2079 
2080  // Return
2081  return;
2082 }
2083 
2084 /***********************************************************************//**
2085  * @brief Notify client about VO table loading
2086  *
2087  * @param[in] client Client.
2088  * @param[in] xml Message from which table information is extracted.
2089  *
2090  * Notify a client that a VO table is avialable for loading. The method sends
2091  * sends a "table.load.votable" message to the @p client. Information about
2092  * the VO table is extracted from the @p xml document.
2093  ***************************************************************************/
2095  const GXml& xml)
2096 {
2097  // Get client response
2098  const GXmlNode* node = xml.element("methodCall > params > param[1] > "
2099  "value > struct > member > value > "
2100  "struct");
2101 
2102  // Extract image information from client response
2103  std::string name = get_response_value(node, "name");
2104  std::string url = get_response_value(node, "url");
2105  std::string id = get_response_value(node, "table-id");
2106 
2107  // Declare notification
2108  std::string msg = "";
2109 
2110  // Set notification for table.load.votable
2111  msg.append("<?xml version=\"1.0\"?>\n");
2112  msg.append("<methodCall>\n");
2113  msg.append("<methodName>samp.client.receiveNotification</methodName>\n");
2114  msg.append("<params>\n");
2115  msg.append(" <param><value>"+client.private_key+"</value></param>\n");
2116  msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
2117  msg.append(" <param><value><struct>\n");
2118  msg.append(" <member>\n");
2119  msg.append(" <name>samp.mtype</name>\n");
2120  msg.append(" <value>table.load.votable</value>\n");
2121  msg.append(" </member>\n");
2122  msg.append(" <member>\n");
2123  msg.append(" <name>samp.params</name>\n");
2124  msg.append(" <value><struct>\n");
2125  msg.append(" <member>\n");
2126  msg.append(" <name>name</name>\n");
2127  msg.append(" <value>"+name+"</value>\n");
2128  msg.append(" </member>\n");
2129  msg.append(" <member>\n");
2130  msg.append(" <name>table-id</name>\n");
2131  msg.append(" <value>"+id+"</value>\n");
2132  msg.append(" </member>\n");
2133  msg.append(" <member>\n");
2134  msg.append(" <name>url</name>\n");
2135  msg.append(" <value>"+url+"</value>\n");
2136  msg.append(" </member>\n");
2137  msg.append(" </struct></value>\n");
2138  msg.append(" </member>\n");
2139  msg.append(" </struct></value></param>\n");
2140  msg.append("</params>\n");
2141  msg.append("</methodCall>\n");
2142 
2143  // Post notification
2144  notify(client.url, msg);
2145 
2146  // Return
2147  return;
2148 }
2149 
2150 
2151 /***********************************************************************//**
2152  * @brief Generates random string of characters
2153  *
2154  * @param[in] length Length of random string
2155  ***************************************************************************/
2156 std::string GVOHub::random_string(const size_t& length) const
2157 {
2158  srand(time(0));
2159  std::string str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmno"
2160  "pqrstuvwxyz";
2161  while(str.size() != length) {
2162  int pos = ((rand() % (str.size() - 1)));
2163  str.erase(pos, 1);
2164  }
2165 
2166  // Return string
2167  return str;
2168 }
2169 
2170 
2171 /***********************************************************************//**
2172  * @brief Extract mtype from XML request
2173  *
2174  * @param[in] xml XML message sent by client.
2175  *
2176  * Extracts the mtype identifying calling message from the XML request.
2177  ***************************************************************************/
2178 std::string GVOHub::get_mtype(const GXml& xml) const
2179 {
2180  // Header
2181  #if defined(G_CONSOLE_DUMP)
2182  std::cout << "In GVOHub::get_mtype" << std::endl;
2183  #endif
2184 
2185  // Get the XML node containing the client's private key
2186  const GXmlNode* node = xml.element("methodCall > params > param[1] > "
2187  "value > struct ");
2188 
2189  // Get the client's private key
2190  std::string client_key = get_response_value(node, "samp.mtype");
2191 
2192  // Return key
2193  return client_key;
2194 }
2195 
2196 
2197 /***********************************************************************//**
2198  * @brief Return Hub URL
2199  *
2200  * @return Hub URL.
2201  *
2202  * Returns the XML-RPC endpoint for communication with the hub.
2203  ***************************************************************************/
2204 std::string GVOHub::hub_url(void) const
2205 {
2206  // Set Hub URL
2207  std::string hub_url = "http://"+m_hub_host+":"+m_hub_port+"/"+m_hub_path;
2208 
2209  // Return Hub URL
2210  return (hub_url);
2211 }
2212 
2213 
2214 /***********************************************************************//**
2215  * @brief Return client name from XML message
2216  *
2217  * @param[in] xml XML message sent by client.
2218  *
2219  * Returns client name from XML message.
2220  ***************************************************************************/
2221 std::string GVOHub::get_client_name(const GXml& xml) const
2222 {
2223  // Initialise client name
2224  std::string client_name = "";
2225 
2226  // Get the client name
2227  const GXmlNode* node = xml.element("methodCall > params > param[1] > value");
2228  if (node != NULL) {
2229  const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
2230  if (text != NULL) {
2231  client_name = text->text();
2232  }
2233  }
2234 
2235  // Return client name
2236  return client_name;
2237 }
Abstract XML node base class.
Definition: GXmlNode.hpp:57
std::vector< std::string > get_subscriptions(const GXml &xml) const
Returns subscriptions from XML document.
Definition: GVOHub.cpp:1353
void xml_get_name_value_pair(const GXmlNode *node, std::string &name, std::string &value)
Extract name / value pair from XML node.
Definition: GTools.cpp:1988
std::string m_hub_id
Hub identifier used by the hub when it sends message itself rather than forwarding from others...
Definition: GVOHub.hpp:154
std::string url
Definition: GVOHub.hpp:120
void handle_request(const socklen_t &sock)
Reads the client message and runs appropriate function.
Definition: GVOHub.cpp:366
std::string hub_url(void) const
Return Hub URL.
Definition: GVOHub.cpp:2204
std::string getenv(const std::string &arg)
Return value of environment variable.
Definition: GTools.cpp:465
std::string private_key
Definition: GVOHub.hpp:111
void post_samp_void(const socklen_t &sock) const
Post SAMP void massage to client.
Definition: GVOHub.cpp:1671
void delete_samp_file(void) const
Delete the lockfile.
Definition: GVOHub.cpp:1500
std::string print(const GChatter &chatter=NORMAL) const
Print VO hub information.
Definition: GVOHub.cpp:200
GVOHub & operator=(const GVOHub &hub)
Assignment operator.
Definition: GVOHub.cpp:126
XML class interface definition.
void free_members(void)
Delete class members.
Definition: GVOHub.cpp:281
void post_samp_ok(const socklen_t &sock) const
Post SAMP ok massage to client.
Definition: GVOHub.cpp:1637
void request_declare_subscriptions(const GXml &xml, const socklen_t &sock)
Handles subscriptions declaration requests.
Definition: GVOHub.cpp:718
void request_get_subscriptions(const GXml &xml, const socklen_t &sock)
Handles subscriptions getting requests.
Definition: GVOHub.cpp:810
void notify_metadata(const client &client, const std::string &reference)
Notify client about the metadata of another client.
Definition: GVOHub.cpp:1930
void request_register(const GXml &xml, const socklen_t &sock)
Handles registration requests.
Definition: GVOHub.cpp:510
GVOHub(void)
Void constructor.
Definition: GVOHub.cpp:73
int recv(int fd, char *buffer, int len, int flags, int timeout)
Checks whether a parameter has occured once.
Definition: GTools.cpp:2036
std::string get_mtype(const GXml &xml) const
Extract mtype from XML request.
Definition: GVOHub.cpp:2178
void request_get_subscribed_clients(const GXml &xml, const socklen_t &sock)
Handles subscribed client information requests.
Definition: GVOHub.cpp:937
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition: GXmlNode.cpp:586
#define G_GET_SOCKET
Definition: GVOHub.cpp:52
Gammalib tools definition.
std::string m_hub_path
Hub path.
Definition: GVOHub.hpp:152
void request_get_registered_clients(const GXml &xml, const socklen_t &sock)
Handles registered client information requests.
Definition: GVOHub.cpp:887
void init_members(void)
Initialise class members.
Definition: GVOHub.cpp:237
virtual ~GVOHub(void)
Destructor.
Definition: GVOHub.cpp:104
std::string random_string(const size_t &length) const
Generates random string of characters.
Definition: GVOHub.cpp:2156
void start_hub(void)
Starts the SAMP hub socket and listens on it.
Definition: GVOHub.cpp:305
GXmlElement * element(const int &index)
Return pointer to child element.
Definition: GXml.cpp:419
XML class.
Definition: GXml.hpp:172
std::string reference
Definition: GVOHub.hpp:112
std::string m_secret
Secret Hub key.
Definition: GVOHub.hpp:149
XML text node class.
Definition: GXmlText.hpp:43
SAMP hub class interface definition.
const std::string & text(void) const
Return text.
Definition: GXmlText.hpp:97
std::vector< client > m_clients
Clients.
Definition: GVOHub.hpp:157
#define G_START_HUB
Definition: GVOHub.cpp:51
void notify_register(const client &client, const std::string &reference)
Notify client about another client registering at Hub.
Definition: GVOHub.cpp:1834
void request_declare_metadata(const GXml &xml, const socklen_t &sock)
Handles metadata declaration requests.
Definition: GVOHub.cpp:654
std::string get_hub_lockfile(void) const
Returns SAMP Hub lockfile URL.
Definition: GVOHub.cpp:1415
void start(void)
Start Hub.
Definition: GVOHub.cpp:184
GChatter
Definition: GTypemaps.hpp:33
std::string get_client_key(const GXml &xml) const
Extract client key from XML request.
Definition: GVOHub.cpp:1197
void request_get_metadata(const GXml &xml, const socklen_t &sock)
Handles a metadata requests.
Definition: GVOHub.cpp:979
VO SAMP Hub class.
Definition: GVOHub.hpp:51
void request_notify_all(const GXml &xml, const socklen_t &sock)
Handle request to notify all clients.
Definition: GVOHub.cpp:1117
GVOHub * clone(void) const
Clone object.
Definition: GVOHub.cpp:174
void post_string(const std::string &content, const socklen_t &sock) const
Post string content to client.
Definition: GVOHub.cpp:1584
void request_unregister(const GXml &xml, const socklen_t &sock)
Handles unregistration requests.
Definition: GVOHub.cpp:600
std::string m_version
The version of the SAMP Standard Profile implemented by the hub.
Definition: GVOHub.hpp:153
void request_shutdown(const socklen_t &sock)
Handles Hub shutdown requests.
Definition: GVOHub.cpp:1172
bool m_shutdown
Shutdown request.
Definition: GVOHub.hpp:156
std::string get_response_value(const GXmlNode *node, const std::string &name) const
Returns value for a named parameter.
Definition: GVOHub.cpp:1311
virtual GXmlElement * element(const int &index)
Return pointer to GXMLElement child.
Definition: GXmlNode.cpp:640
void clear(void)
Clear object.
Definition: GVOHub.cpp:158
void request_set_xml_rpc_callback(const GXml &xml, const socklen_t &sock)
Handles XML-RPC callback setting requests.
Definition: GVOHub.cpp:766
void notify_table_load(const GVOHub::client &client, const GXml &xml)
Notify client about VO table loading.
Definition: GVOHub.cpp:2094
void notify_unregister(const client &client, const std::string &reference)
Notify client about another client unregistering at Hub.
Definition: GVOHub.cpp:1882
void create_samp_file(void) const
Create the lockfile.
Definition: GVOHub.cpp:1465
std::string get_client_name(const GXml &xml) const
Return client name from XML message.
Definition: GVOHub.cpp:2221
Exception handler interface definition.
std::string m_hub_port
Hub port.
Definition: GVOHub.hpp:151
void request_ping(const socklen_t &sock)
Handles ping requests.
Definition: GVOHub.cpp:487
void copy_members(const GVOHub &client)
Copy class members.
Definition: GVOHub.cpp:260
void notify(const std::string &url, const std::string &notification) const
Send notification to client.
Definition: GVOHub.cpp:1702
std::string get_callback_url(const GXml &xml) const
Returns callback URL of client.
Definition: GVOHub.cpp:1388
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
Definition: GXmlNode.cpp:287
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
int get_socket(void)
Get Hub socket.
Definition: GVOHub.cpp:1521
int m_socket
Hub socket.
Definition: GVOHub.hpp:155
Abstract XML node base class interface definition.
std::string m_hub_host
Hub host.
Definition: GVOHub.hpp:150
int get_client_index(const GXml &xml) const
Extract client index in shared memory from XML request.
Definition: GVOHub.cpp:1230
void notify_image_load(const client &client, const GXml &xml)
Notify client about image loading.
Definition: GVOHub.cpp:2028
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489