GammaLib 2.0.0
Loading...
Searching...
No Matches
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
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
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 ***************************************************************************/
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 ***************************************************************************/
175{
176 // Clone client
177 return new GVOHub(*this);
178}
179
180
181/***********************************************************************//**
182 * @brief Start Hub
183 ***************************************************************************/
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 ***************************************************************************/
200std::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
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 ***************************************************************************/
261{
262 // Copy members
263 m_secret = hub.m_secret;
267 m_version = hub.m_version;
268 m_hub_id = hub.m_hub_id;
269 m_socket = hub.m_socket;
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
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 ***************************************************************************/
366void 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) {
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 ***************************************************************************/
487void 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 ***************************************************************************/
510void 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 ***************************************************************************/
600void 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 ***************************************************************************/
654void 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 ***************************************************************************/
718void 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 ***************************************************************************/
810void 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 ***************************************************************************/
887void 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 ***************************************************************************/
937void 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 ***************************************************************************/
979void 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 ***************************************************************************/
1117void 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") {
1146 }
1147
1148 // ... or VO table loading?
1149 else if (mtype == "table.load.votable") {
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 ***************************************************************************/
1172void 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 ***************************************************************************/
1197std::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 ***************************************************************************/
1230int 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 ***************************************************************************/
1270int 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 ***************************************************************************/
1311std::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 ***************************************************************************/
1353std::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 ***************************************************************************/
1388std::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 ***************************************************************************/
1415std::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 ***************************************************************************/
1584void 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 ***************************************************************************/
1637void 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 ***************************************************************************/
1671void 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 ***************************************************************************/
1702void 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 ***************************************************************************/
2156std::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 ***************************************************************************/
2178std::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 ***************************************************************************/
2204std::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 ***************************************************************************/
2221std::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}
Exception handler interface definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
#define G_START_HUB
Definition GVOHub.cpp:51
#define G_GET_SOCKET
Definition GVOHub.cpp:52
SAMP hub class interface definition.
Abstract XML node base class interface definition.
XML class interface definition.
VO SAMP Hub class.
Definition GVOHub.hpp:51
void clear(void)
Clear object.
Definition GVOHub.cpp:158
std::vector< client > m_clients
Clients.
Definition GVOHub.hpp:157
std::string get_hub_lockfile(void) const
Returns SAMP Hub lockfile URL.
Definition GVOHub.cpp:1415
std::string m_secret
Secret Hub key.
Definition GVOHub.hpp:149
std::string get_client_name(const GXml &xml) const
Return client name from XML message.
Definition GVOHub.cpp:2221
std::string get_mtype(const GXml &xml) const
Extract mtype from XML request.
Definition GVOHub.cpp:2178
void start_hub(void)
Starts the SAMP hub socket and listens on it.
Definition GVOHub.cpp:305
void request_get_metadata(const GXml &xml, const socklen_t &sock)
Handles a metadata requests.
Definition GVOHub.cpp:979
void request_get_registered_clients(const GXml &xml, const socklen_t &sock)
Handles registered client information requests.
Definition GVOHub.cpp:887
void start(void)
Start Hub.
Definition GVOHub.cpp:184
void request_set_xml_rpc_callback(const GXml &xml, const socklen_t &sock)
Handles XML-RPC callback setting requests.
Definition GVOHub.cpp:766
void create_samp_file(void) const
Create the lockfile.
Definition GVOHub.cpp:1465
int get_client_index(const GXml &xml) const
Extract client index in shared memory from XML request.
Definition GVOHub.cpp:1230
void request_register(const GXml &xml, const socklen_t &sock)
Handles registration requests.
Definition GVOHub.cpp:510
void notify_image_load(const client &client, const GXml &xml)
Notify client about image loading.
Definition GVOHub.cpp:2028
std::string m_hub_path
Hub path.
Definition GVOHub.hpp:152
std::string get_client_key(const GXml &xml) const
Extract client key from XML request.
Definition GVOHub.cpp:1197
virtual ~GVOHub(void)
Destructor.
Definition GVOHub.cpp:104
void post_samp_ok(const socklen_t &sock) const
Post SAMP ok massage to client.
Definition GVOHub.cpp:1637
void free_members(void)
Delete class members.
Definition GVOHub.cpp:281
std::string get_response_value(const GXmlNode *node, const std::string &name) const
Returns value for a named parameter.
Definition GVOHub.cpp:1311
int get_socket(void)
Get Hub socket.
Definition GVOHub.cpp:1521
void copy_members(const GVOHub &client)
Copy class members.
Definition GVOHub.cpp:260
void init_members(void)
Initialise class members.
Definition GVOHub.cpp:237
void notify(const std::string &url, const std::string &notification) const
Send notification to client.
Definition GVOHub.cpp:1702
void request_notify_all(const GXml &xml, const socklen_t &sock)
Handle request to notify all clients.
Definition GVOHub.cpp:1117
void request_declare_subscriptions(const GXml &xml, const socklen_t &sock)
Handles subscriptions declaration requests.
Definition GVOHub.cpp:718
GVOHub & operator=(const GVOHub &hub)
Assignment operator.
Definition GVOHub.cpp:126
void notify_register(const client &client, const std::string &reference)
Notify client about another client registering at Hub.
Definition GVOHub.cpp:1834
void request_shutdown(const socklen_t &sock)
Handles Hub shutdown requests.
Definition GVOHub.cpp:1172
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 get_callback_url(const GXml &xml) const
Returns callback URL of client.
Definition GVOHub.cpp:1388
std::string hub_url(void) const
Return Hub URL.
Definition GVOHub.cpp:2204
std::string random_string(const size_t &length) const
Generates random string of characters.
Definition GVOHub.cpp:2156
std::vector< std::string > get_subscriptions(const GXml &xml) const
Returns subscriptions from XML document.
Definition GVOHub.cpp:1353
void request_ping(const socklen_t &sock)
Handles ping requests.
Definition GVOHub.cpp:487
void post_samp_void(const socklen_t &sock) const
Post SAMP void massage to client.
Definition GVOHub.cpp:1671
void handle_request(const socklen_t &sock)
Reads the client message and runs appropriate function.
Definition GVOHub.cpp:366
void request_unregister(const GXml &xml, const socklen_t &sock)
Handles unregistration requests.
Definition GVOHub.cpp:600
void request_get_subscribed_clients(const GXml &xml, const socklen_t &sock)
Handles subscribed client information requests.
Definition GVOHub.cpp:937
void request_get_subscriptions(const GXml &xml, const socklen_t &sock)
Handles subscriptions getting requests.
Definition GVOHub.cpp:810
void delete_samp_file(void) const
Delete the lockfile.
Definition GVOHub.cpp:1500
void notify_metadata(const client &client, const std::string &reference)
Notify client about the metadata of another client.
Definition GVOHub.cpp:1930
void notify_table_load(const GVOHub::client &client, const GXml &xml)
Notify client about VO table loading.
Definition GVOHub.cpp:2094
std::string m_hub_port
Hub port.
Definition GVOHub.hpp:151
std::string m_hub_host
Hub host.
Definition GVOHub.hpp:150
GVOHub(void)
Void constructor.
Definition GVOHub.cpp:73
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
std::string m_version
The version of the SAMP Standard Profile implemented by the hub.
Definition GVOHub.hpp:153
void notify_unregister(const client &client, const std::string &reference)
Notify client about another client unregistering at Hub.
Definition GVOHub.cpp:1882
void request_declare_metadata(const GXml &xml, const socklen_t &sock)
Handles metadata declaration requests.
Definition GVOHub.cpp:654
int m_socket
Hub socket.
Definition GVOHub.hpp:155
std::string print(const GChatter &chatter=NORMAL) const
Print VO hub information.
Definition GVOHub.cpp:200
bool m_shutdown
Shutdown request.
Definition GVOHub.hpp:156
const std::string & name(void) const
Return XML element name.
Abstract XML node base class.
Definition GXmlNode.hpp:57
virtual GXmlElement * element(const int &index)
Return pointer to GXMLElement child.
Definition GXmlNode.cpp:640
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition GXmlNode.cpp:586
XML text node class.
Definition GXmlText.hpp:43
const std::string & text(void) const
Return text.
Definition GXmlText.hpp:97
XML class.
Definition GXml.hpp:172
GXmlElement * element(const int &index)
Return pointer to child element.
Definition GXml.cpp:419
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
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
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 private_key
Definition GVOHub.hpp:111
std::string reference
Definition GVOHub.hpp:112
std::string url
Definition GVOHub.hpp:120