summaryrefslogtreecommitdiff
path: root/cpp/src/IceGrid/Client.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IceGrid/Client.cpp')
-rw-r--r--cpp/src/IceGrid/Client.cpp796
1 files changed, 796 insertions, 0 deletions
diff --git a/cpp/src/IceGrid/Client.cpp b/cpp/src/IceGrid/Client.cpp
new file mode 100644
index 00000000000..1738873f596
--- /dev/null
+++ b/cpp/src/IceGrid/Client.cpp
@@ -0,0 +1,796 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceUtil/DisableWarnings.h>
+#include <IceUtil/Options.h>
+#include <IceUtil/CtrlCHandler.h>
+#include <IceUtil/Thread.h>
+#include <IceUtil/StringUtil.h>
+#include <IceUtil/UUID.h>
+#include <IceUtil/Mutex.h>
+#include <IceUtil/MutexPtrLock.h>
+#include <Ice/Ice.h>
+#include <Ice/SliceChecksums.h>
+#include <IceGrid/Parser.h>
+#include <IceGrid/FileParserI.h>
+#include <IceGrid/Registry.h>
+#include <IceGrid/Locator.h>
+#include <Glacier2/Router.h>
+#include <fstream>
+
+//
+// For getPassword()
+//
+#ifndef _WIN32
+# include <termios.h>
+#else
+# include <conio.h>
+#endif
+
+using namespace std;
+//using namespace Ice; // COMPILERFIX: VC6 reports compilation error because of ambiguous Locator symbol.
+using namespace IceGrid;
+
+class Client;
+
+namespace
+{
+
+IceUtil::Mutex* _staticMutex = 0;
+Client* _globalClient = 0;
+
+class Init
+{
+public:
+
+ Init()
+ {
+ _staticMutex = new IceUtil::Mutex;
+ }
+
+ ~Init()
+ {
+ delete _staticMutex;
+ _staticMutex = 0;
+ }
+};
+
+Init init;
+
+}
+
+class SessionKeepAliveThread : public IceUtil::Thread, public IceUtil::Monitor<IceUtil::Mutex>
+{
+public:
+
+ SessionKeepAliveThread(const AdminSessionPrx& session, long timeout) :
+ IceUtil::Thread("IceGrid admin session keepalive thread"),
+ _session(session),
+ _timeout(IceUtil::Time::seconds(timeout)),
+ _destroy(false)
+ {
+ }
+
+ virtual void
+ run()
+ {
+ Lock sync(*this);
+ while(!_destroy)
+ {
+ timedWait(_timeout);
+ if(_destroy)
+ {
+ break;
+ }
+ try
+ {
+ _session->keepAlive();
+ }
+ catch(const Ice::Exception&)
+ {
+ break;
+ }
+ }
+ }
+
+ void
+ destroy()
+ {
+ Lock sync(*this);
+ _destroy = true;
+ notify();
+ }
+
+private:
+
+ AdminSessionPrx _session;
+ const IceUtil::Time _timeout;
+ bool _destroy;
+};
+typedef IceUtil::Handle<SessionKeepAliveThread> SessionKeepAliveThreadPtr;
+
+class ReuseConnectionRouter : public Ice::Router
+{
+public:
+
+ ReuseConnectionRouter(const Ice::ObjectPrx& proxy) : _clientProxy(proxy)
+ {
+ }
+
+ virtual Ice::ObjectPrx
+ getClientProxy(const Ice::Current&) const
+ {
+ return _clientProxy;
+ }
+
+ virtual Ice::ObjectPrx
+ getServerProxy(const Ice::Current&) const
+ {
+ return 0;
+ }
+
+ virtual void
+ addProxy(const Ice::ObjectPrx&, const Ice::Current&)
+ {
+ }
+
+ virtual Ice::ObjectProxySeq
+ addProxies(const Ice::ObjectProxySeq&, const Ice::Current&)
+ {
+ return Ice::ObjectProxySeq();
+ }
+
+private:
+
+ const Ice::ObjectPrx _clientProxy;
+};
+
+class Client : public IceUtil::Monitor<IceUtil::Mutex>
+{
+public:
+
+ void usage();
+ int main(Ice::StringSeq& args);
+ int run(Ice::StringSeq& args);
+ void interrupted();
+
+ Ice::CommunicatorPtr communicator() const { return _communicator; }
+ const string& appName() const { return _appName; }
+
+ string getPassword(const string&);
+
+private:
+
+ IceUtil::CtrlCHandler _ctrlCHandler;
+ Ice::CommunicatorPtr _communicator;
+ string _appName;
+ ParserPtr _parser;
+};
+
+static void
+interruptCallback(int signal)
+{
+ IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(_staticMutex);
+ if(_globalClient)
+ {
+ _globalClient->interrupted();
+ }
+}
+
+//COMPILERFIX: Borland C++ 2010 doesn't support wmain for console applications.
+#if defined(_WIN32 ) && !defined(__BCPLUSPLUS__)
+
+int
+wmain(int argc, wchar_t* argv[])
+
+#else
+
+int
+main(int argc, char* argv[])
+
+#endif
+{
+ Client app;
+ Ice::StringSeq args = Ice::argsToStringSeq(argc, argv);
+ return app.main(args);
+}
+
+void
+Client::usage()
+{
+ cerr << "Usage: " << appName() << " [options]\n";
+ cerr <<
+ "Options:\n"
+ "-h, --help Show this message.\n"
+ "-v, --version Display the Ice version.\n"
+ "-e COMMANDS Execute COMMANDS.\n"
+ "-d, --debug Print debug messages.\n"
+ "-s, --server Start icegridadmin as a server (to parse XML files).\n"
+ "-u, --username Login with the given username.\n"
+ "-p, --password Login with the given password.\n"
+ "-S, --ssl Authenticate through SSL.\n"
+ "-r, --replica NAME Connect to the replica NAME.\n"
+ ;
+}
+
+
+int
+Client::main(Ice::StringSeq& args)
+{
+ int status = EXIT_SUCCESS;
+
+ try
+ {
+ _appName = args[0];
+ Ice::InitializationData id;
+ id.properties = Ice::createProperties(args);
+ //
+ // We don't want to load DB plug-ins with icegridadmin, as this will
+ // cause FileLock issues when run with the same configuration file
+ // used by the service.
+ //
+ id.properties->setProperty("Ice.Plugin.DB", "");
+ _communicator = Ice::initialize(id);
+
+ {
+ IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(_staticMutex);
+ _globalClient = this;
+ }
+ _ctrlCHandler.setCallback(interruptCallback);
+
+ try
+ {
+ status = run(args);
+ }
+ catch(const Ice::CommunicatorDestroyedException&)
+ {
+ // Expected if the client is interrupted during the initialization.
+ }
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << _appName << ": " << ex << endl;
+ status = EXIT_FAILURE;
+ }
+ catch(const std::exception& ex)
+ {
+ cerr << _appName << ": std::exception: " << ex.what() << endl;
+ status = EXIT_FAILURE;
+ }
+ catch(const std::string& msg)
+ {
+ cerr << _appName << ": " << msg << endl;
+ status = EXIT_FAILURE;
+ }
+ catch(const char* msg)
+ {
+ cerr << _appName << ": " << msg << endl;
+ status = EXIT_FAILURE;
+ }
+ catch(...)
+ {
+ cerr << _appName << ": unknown exception" << endl;
+ status = EXIT_FAILURE;
+ }
+
+ if(_communicator)
+ {
+ try
+ {
+ _communicator->destroy();
+ }
+ catch(const Ice::CommunicatorDestroyedException&)
+ {
+ }
+ catch(const Ice::Exception& ex)
+ {
+ cerr << ex << endl;
+ status = EXIT_FAILURE;
+ }
+ }
+
+ _ctrlCHandler.setCallback(0);
+ {
+ IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(_staticMutex);
+ _globalClient = 0;
+ }
+
+ return status;
+
+}
+
+void
+Client::interrupted()
+{
+ Lock sync(*this);
+ if(_parser) // If there's an interactive parser, notify the parser.
+ {
+ _parser->interrupt();
+ }
+ else
+ {
+ //
+ // Otherwise, destroy the communicator.
+ //
+ assert(_communicator);
+ try
+ {
+ _communicator->destroy();
+ }
+ catch(const Ice::Exception&)
+ {
+ }
+ }
+}
+
+int
+Client::run(Ice::StringSeq& originalArgs)
+{
+ string commands;
+ bool debug;
+
+ IceUtilInternal::Options opts;
+ opts.addOpt("h", "help");
+ opts.addOpt("v", "version");
+ opts.addOpt("e", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
+ opts.addOpt("u", "username", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::NoRepeat);
+ opts.addOpt("p", "password", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::NoRepeat);
+ opts.addOpt("S", "ssl");
+ opts.addOpt("d", "debug");
+ opts.addOpt("s", "server");
+ opts.addOpt("r", "replica", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::NoRepeat);
+
+ vector<string> args;
+ try
+ {
+ args = opts.parse(originalArgs);
+ }
+ catch(const IceUtilInternal::BadOptException& e)
+ {
+ cerr << e.reason << endl;
+ usage();
+ return EXIT_FAILURE;
+ }
+ if(!args.empty())
+ {
+ cerr << _appName << ": too many arguments" << endl;
+ usage();
+ return EXIT_FAILURE;
+ }
+
+ if(opts.isSet("help"))
+ {
+ usage();
+ return EXIT_SUCCESS;
+ }
+ if(opts.isSet("version"))
+ {
+ cout << ICE_STRING_VERSION << endl;
+ return EXIT_SUCCESS;
+ }
+
+ if(opts.isSet("server"))
+ {
+ Ice::ObjectAdapterPtr adapter =
+ communicator()->createObjectAdapterWithEndpoints("FileParser", "tcp -h localhost");
+ adapter->activate();
+ Ice::ObjectPrx proxy = adapter->add(new FileParserI, communicator()->stringToIdentity("FileParser"));
+ cout << proxy << endl;
+
+ communicator()->waitForShutdown();
+ return EXIT_SUCCESS;
+ }
+
+ if(opts.isSet("e"))
+ {
+ vector<string> optargs = opts.argVec("e");
+ for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
+ {
+ commands += *i + ";";
+ }
+ }
+ debug = opts.isSet("debug");
+
+ bool ssl = communicator()->getProperties()->getPropertyAsInt("IceGridAdmin.AuthenticateUsingSSL");
+ if(opts.isSet("ssl"))
+ {
+ ssl = true;
+ }
+
+ string id = communicator()->getProperties()->getProperty("IceGridAdmin.Username");
+ if(!opts.optArg("username").empty())
+ {
+ id = opts.optArg("username");
+ }
+ string password = communicator()->getProperties()->getProperty("IceGridAdmin.Password");
+ if(!opts.optArg("password").empty())
+ {
+ password = opts.optArg("password");
+ }
+
+ Ice::PropertiesPtr properties = communicator()->getProperties();
+ string replica = properties->getProperty("IceGridAdmin.Replica");
+ if(!opts.optArg("replica").empty())
+ {
+ replica = opts.optArg("replica");
+ }
+
+ Glacier2::RouterPrx router;
+ AdminSessionPrx session;
+ SessionKeepAliveThreadPtr keepAlive;
+ int status = EXIT_SUCCESS;
+ try
+ {
+ int timeout;
+ if(communicator()->getDefaultRouter())
+ {
+ try
+ {
+ // Use SSL if available.
+ router = Glacier2::RouterPrx::checkedCast(communicator()->getDefaultRouter()->ice_preferSecure(true));
+ if(!router)
+ {
+ cerr << _appName << ": configured router is not a Glacier2 router" << endl;
+ return EXIT_FAILURE;
+ }
+ }
+ catch(const Ice::LocalException& ex)
+ {
+ cerr << _appName << ": could not contact the default router:" << endl << ex << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(ssl)
+ {
+ session = AdminSessionPrx::uncheckedCast(router->createSessionFromSecureConnection());
+ if(!session)
+ {
+ cerr << _appName
+ << ": Glacier2 returned a null session, please set the Glacier2.SSLSessionManager property"
+ << endl;
+ return EXIT_FAILURE;
+ }
+ }
+ else
+ {
+ while(id.empty() && cin.good())
+ {
+ cout << "user id: " << flush;
+ getline(cin, id);
+ if(!cin.good())
+ {
+ return EXIT_FAILURE;
+ }
+ id = IceUtilInternal::trim(id);
+ }
+
+ if(password.empty())
+ {
+ password = getPassword("password: ");
+#ifndef _WIN32
+ if(!cin.good())
+ {
+ return EXIT_FAILURE;
+ }
+#endif
+ }
+
+ session = AdminSessionPrx::uncheckedCast(router->createSession(id, password));
+ // Zero the password string.
+ for(string::iterator p = password.begin(); p != password.end(); ++p)
+ {
+ *p = '\0';
+ }
+ if(!session)
+ {
+ cerr << _appName
+ << ": Glacier2 returned a null session, please set the Glacier2.SessionManager property"
+ << endl;
+ return EXIT_FAILURE;
+ }
+ }
+ timeout = static_cast<int>(router->getSessionTimeout());
+ }
+ else if(communicator()->getDefaultLocator())
+ {
+ //
+ // Create the identity of the registry to connect to.
+ //
+ Ice::Identity registryId;
+ registryId.category = communicator()->getDefaultLocator()->ice_getIdentity().category;
+ registryId.name = "Registry";
+ if(!replica.empty() && replica != "Master")
+ {
+ registryId.name += "-" + replica;
+ }
+
+ //
+ // First try to contact the locator. If we can't talk to the locator,
+ // no need to go further. Otherwise, we get the proxy of local registry
+ // proxy.
+ //
+ IceGrid::LocatorPrx locator;
+ RegistryPrx localRegistry;
+ try
+ {
+ locator = IceGrid::LocatorPrx::checkedCast(communicator()->getDefaultLocator());
+ if(!locator)
+ {
+ cerr << _appName << ": configured locator is not an IceGrid locator" << endl;
+ return EXIT_FAILURE;
+ }
+ localRegistry = locator->getLocalRegistry();
+ }
+ catch(const Ice::LocalException& ex)
+ {
+ cerr << _appName << ": could not contact the default locator:" << endl << ex << endl;
+ return EXIT_FAILURE;
+ }
+
+ IceGrid::RegistryPrx registry;
+ if(localRegistry->ice_getIdentity() == registryId)
+ {
+ registry = localRegistry;
+ }
+ else
+ {
+ //
+ // The locator local registry isn't the registry we want to connect to.
+ //
+
+ try
+ {
+ const string strId = "\"" + communicator()->identityToString(registryId) + "\"";
+ registry = RegistryPrx::checkedCast(communicator()->stringToProxy(strId));
+ if(!registry)
+ {
+ cerr << _appName << ": could not contact an IceGrid registry" << endl;
+ }
+ }
+ catch(const Ice::NotRegisteredException&)
+ {
+ cerr << _appName << ": no active registry replica named `" << replica << "'" << endl;
+ return EXIT_FAILURE;
+ }
+ catch(const Ice::LocalException& ex)
+ {
+ if(!replica.empty())
+ {
+ cerr << _appName << ": could not contact the registry replica named `" << replica << "':\n";
+ cerr << ex << endl;
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ //
+ // If we can't contact the master, use to the local registry.
+ //
+ registry = localRegistry;
+ string name = registry->ice_getIdentity().name;
+ const string prefix("Registry-");
+ string::size_type pos = name.find(prefix);
+ if(pos != string::npos)
+ {
+ name = name.substr(prefix.size());
+ }
+ cerr << _appName << ": warning: could not contact master, using slave `" << name << "'" << endl;
+ }
+ }
+ }
+
+ //
+ // If the registry to use is the locator local registry, we install a default router
+ // to ensure we'll use a single connection regardless of the endpoints returned in the
+ // proxies of the various session/admin methods (useful if used over an ssh tunnel).
+ //
+ if(registry->ice_getIdentity() == localRegistry->ice_getIdentity())
+ {
+ properties->setProperty("CollocInternal.AdapterId", IceUtil::generateUUID());
+ Ice::ObjectAdapterPtr colloc = communicator()->createObjectAdapter("CollocInternal");
+ colloc->setLocator(0);
+ Ice::ObjectPrx router = colloc->addWithUUID(new ReuseConnectionRouter(locator));
+ communicator()->setDefaultRouter(Ice::RouterPrx::uncheckedCast(router));
+ registry = registry->ice_router(communicator()->getDefaultRouter());
+ }
+
+ // Prefer SSL.
+ registry = registry->ice_preferSecure(true);
+
+ if(ssl)
+ {
+ session = registry->createAdminSessionFromSecureConnection();
+ }
+ else
+ {
+ while(id.empty() && cin.good())
+ {
+ cout << "user id: " << flush;
+ getline(cin, id);
+ if(!cin.good())
+ {
+ return EXIT_FAILURE;
+ }
+ id = IceUtilInternal::trim(id);
+ }
+
+ if(password.empty())
+ {
+ password = getPassword("password: ");
+#ifndef _WIN32
+ if(!cin.good())
+ {
+ return EXIT_FAILURE;
+ }
+#endif
+ }
+
+ session = registry->createAdminSession(id, password);
+ // Zero the password string.
+ for(string::iterator p = password.begin(); p != password.end(); ++p)
+ {
+ *p = '\0';
+ }
+ }
+
+ timeout = registry->getSessionTimeout();
+ }
+ else // No default locator or router set.
+ {
+ cerr << _appName << ": could not contact the registry:" << endl;
+ cerr << "no default locator or router configured" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(timeout > 0)
+ {
+ keepAlive = new SessionKeepAliveThread(session, timeout / 2);
+ keepAlive->start();
+ }
+
+ AdminPrx admin = session->getAdmin();
+
+ Ice::SliceChecksumDict serverChecksums = admin->getSliceChecksums();
+ Ice::SliceChecksumDict localChecksums = Ice::sliceChecksums();
+
+ //
+ // The following slice types are only used by the admin CLI.
+ //
+ localChecksums.erase("::IceGrid::FileParser");
+ localChecksums.erase("::IceGrid::ParseException");
+
+ for(Ice::SliceChecksumDict::const_iterator q = localChecksums.begin(); q != localChecksums.end(); ++q)
+ {
+ Ice::SliceChecksumDict::const_iterator r = serverChecksums.find(q->first);
+ if(r == serverChecksums.end())
+ {
+ cerr << appName() << ": server is using unknown Slice type `" << q->first << "'" << endl;
+ }
+ else if(q->second != r->second)
+ {
+ cerr << appName() << ": server is using a different Slice definition of `" << q->first << "'" << endl;
+ }
+ }
+
+ {
+ Lock sync(*this);
+ _parser = Parser::createParser(communicator(), session, admin, commands.empty());
+ }
+
+ if(!commands.empty()) // Commands were given
+ {
+ int parseStatus = _parser->parse(commands, debug);
+ if(parseStatus == EXIT_FAILURE)
+ {
+ status = EXIT_FAILURE;
+ }
+ }
+ else // No commands, let's use standard input
+ {
+ _parser->showBanner();
+
+ int parseStatus = _parser->parse(stdin, debug);
+ if(parseStatus == EXIT_FAILURE)
+ {
+ status = EXIT_FAILURE;
+ }
+ }
+ }
+ catch(const IceGrid::PermissionDeniedException& ex)
+ {
+ cout << "permission denied:\n" << ex.reason << endl;
+ return EXIT_FAILURE;
+ }
+ catch(const Glacier2::PermissionDeniedException& ex)
+ {
+ cout << "permission denied:\n" << ex.reason << endl;
+ return EXIT_FAILURE;
+ }
+ catch(const Glacier2::CannotCreateSessionException& ex)
+ {
+ cout << "session creation failed:\n" << ex.reason << endl;
+ return EXIT_FAILURE;
+ }
+ catch(...)
+ {
+ if(keepAlive)
+ {
+ keepAlive->destroy();
+ keepAlive->getThreadControl().join();
+ }
+
+ try
+ {
+ if(router)
+ {
+ router->destroySession();
+ }
+ else
+ {
+ session->destroy();
+ }
+ }
+ catch(const Ice::Exception&)
+ {
+ }
+ throw;
+ }
+
+ if(keepAlive)
+ {
+ keepAlive->destroy();
+ keepAlive->getThreadControl().join();
+ }
+
+ if(session)
+ {
+ try
+ {
+ if(router)
+ {
+ router->destroySession();
+ }
+ else
+ {
+ session->destroy();
+ }
+ }
+ catch(const Ice::Exception&)
+ {
+ // Ignore. If the registry has been shutdown this will cause
+ // an exception.
+ }
+ }
+
+ return status;
+}
+
+string
+Client::getPassword(const string& prompt)
+{
+ cout << prompt << flush;
+ string password;
+#ifndef _WIN32
+ struct termios oldConf;
+ struct termios newConf;
+ tcgetattr(0, &oldConf);
+ newConf = oldConf;
+ newConf.c_lflag &= (~ECHO);
+ tcsetattr(0, TCSANOW, &newConf);
+ getline(cin, password);
+ tcsetattr(0, TCSANOW, &oldConf);
+#else
+ char c;
+ while((c = _getch()) != '\r')
+ {
+ password += c;
+ }
+#endif
+ cout << endl;
+ return IceUtilInternal::trim(password);
+}