Urbi SDK Remote for C++  2.7.5
liburbi/urbi-launch.cc
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008-2011, Gostai S.A.S.
00003  *
00004  * This software is provided "as is" without warranty of any kind,
00005  * either expressed or implied, including but not limited to the
00006  * implied warranties of fitness for a particular purpose.
00007  *
00008  * See the LICENSE file for more information.
00009  */
00010 
00011 #include <string>
00012 #include <libport/cassert>
00013 #include <cstdarg>
00014 #include <libport/cstdlib>
00015 #include <iostream>
00016 #include <stdexcept>
00017 
00018 #include <boost/assign/list_of.hpp>
00019 using namespace boost::assign;
00020 
00021 #include <libport/cli.hh>
00022 #include <libport/containers.hh>
00023 #include <libport/debug.hh>
00024 #include <libport/file-system.hh>
00025 #include <libport/foreach.hh>
00026 #include <libport/path.hh>
00027 #include <libport/package-info.hh>
00028 #include <libport/program-name.hh>
00029 #include <libport/sysexits.hh>
00030 #include <libport/unistd.h>
00031 #include <libport/windows.hh>
00032 #include <libport/option-parser.hh>
00033 #include <libport/xltdl.hh>
00034 
00035 #include <urbi/exit.hh>
00036 #include <urbi/package-info.hh>
00037 #include <urbi/uclient.hh>
00038 #include <urbi/urbi-root.hh>
00039 
00040 GD_CATEGORY(Urbi.UrbiLaunch);
00041 
00042 using namespace urbi;
00043 using libport::program_name;
00044 
00045 static UCallbackAction
00046 onError(const UMessage& msg)
00047 {
00048   LIBPORT_USE(msg);
00049   GD_FERROR("%s: load module error: %s", program_name(), msg.message);
00050   return URBI_CONTINUE;
00051 }
00052 
00053 static UCallbackAction
00054 onDone(const UMessage&)
00055 {
00056   ::exit(0);
00057 }
00058 
00059 static int
00060 connect_plugin(const std::string& host, int port,
00061                const libport::cli_args_type& modules)
00062 {
00063   UClient cl(host, port);
00064   if (cl.error())
00065     // UClient already displayed an error message.
00066     ::exit(1);
00067   cl.setErrorCallback(callback(&onError));
00068   cl.setCallback(callback(&onDone), "output");
00069   foreach (const std::string& m, modules)
00070     cl << "loadModule(\"" << m << "\");";
00071   cl << "output << 1;";
00072   while (true)
00073     sleep(1);
00074   return 0;
00075 }
00076 
00077 static void
00078 usage(libport::OptionParser& parser)
00079 {
00080   std::cout <<
00081     "usage: " << program_name() <<
00082     " [OPTIONS] MODULE_NAMES ... [-- UOPTIONS...]\n"
00083     "Start an UObject in either remote or plugin mode.\n"
00084               << parser <<
00085     "MODULE_NAMES is a list of modules.\n"
00086     "UOPTIONS are passed to urbi::main in remote and start modes.\n"
00087     "\n"
00088     "Exit values:\n"
00089     "  0  success\n"
00090     " " << EX_NOINPUT << "  some of the MODULES are missing\n"
00091     " " << EX_OSFILE << "  libuobject is missing\n"
00092     "  *  other kinds of errors\n"
00093     ;
00094   ::exit(EX_OK);
00095 }
00096 
00097 
00098 static
00099 void
00100 version()
00101 {
00102   std::cout << urbi::package_info() << std::endl
00103             << libport::exit(EX_OK);
00104 }
00105 
00106 
00107 static
00108 int
00109 urbi_launch_(int argc, const char* argv[], UrbiRoot& urbi_root)
00110 {
00111   libport::program_initialize(argc, argv);
00112 
00113   // The options passed to urbi::main.
00114   libport::cli_args_type args;
00115 
00116   args << argv[0];
00117 
00118   libport::OptionValue
00119     arg_custom("start using the shared library FILE", "custom", 'c', "FILE"),
00120     arg_pfile("file containing the port to listen to", "port-file", 0, "FILE");
00121   libport::OptionFlag
00122     arg_plugin("start as a plugin uobject on a running server", "plugin", 'p'),
00123     arg_remote("start as a remote uobject", "remote", 'r'),
00124     arg_root("output Urbi root and exit", "print-root"),
00125     arg_start("start an urbi server and connect as plugin", "start", 's');
00126   libport::OptionsEnd arg_end;
00127 
00128   libport::OptionParser opt_parser;
00129   opt_parser << "Options:"
00130              << libport::opts::help
00131              << libport::opts::version
00132              << arg_root
00133              << arg_custom
00134 #ifndef LIBPORT_DEBUG_DISABLE
00135              << libport::opts::debug
00136 #endif
00137              << "Mode selection:"
00138              << arg_plugin
00139              << arg_remote
00140              << arg_start
00141              << "Networking:"
00142              << libport::opts::host
00143              << libport::opts::port
00144              << arg_pfile
00145              << arg_end;
00146 
00147   // The list of modules.
00148   libport::cli_args_type modules;
00149   try
00150   {
00151     modules = opt_parser(libport::program_arguments());
00152   }
00153   catch (const libport::Error& e)
00154   {
00155     const libport::Error::errors_type& err = e.errors();
00156     foreach (std::string wrong_arg, err)
00157       libport::invalid_option(wrong_arg);
00158   }
00159 
00160   if (libport::opts::version.get())
00161     version();
00162   if (libport::opts::help.get())
00163     usage(opt_parser);
00164   if (arg_root.get())
00165     std::cout << urbi_root.root() << std::endl << libport::exit(0);
00166 
00167   // Connection mode.
00168   enum ConnectMode
00169   {
00171     MODE_PLUGIN_START,
00173     MODE_PLUGIN_LOAD,
00175     MODE_REMOTE
00176   };
00177   ConnectMode connect_mode = MODE_REMOTE;
00178 
00179   if (arg_plugin.get())
00180     connect_mode = MODE_PLUGIN_LOAD;
00181   if (arg_remote.get())
00182     connect_mode = MODE_REMOTE;
00183   if (arg_start.get())
00184     connect_mode = MODE_PLUGIN_START;
00185 
00187   std::string host = libport::opts::host.value(UClient::default_host());
00188   if (libport::opts::host.filled())
00189     args << "--host" << host;
00190 
00192   int port = libport::opts::port.get<int>(urbi::UClient::URBI_PORT);
00193   if (libport::opts::port.filled())
00194     args << "--port" << libport::opts::port.value();
00195 
00196   if (arg_pfile.filled())
00197   {
00198     std::string file = arg_pfile.value();
00199     if (connect_mode == MODE_PLUGIN_LOAD)
00200       port = libport::file_contents_get<int>(file);
00201     args << "--port-file" << file;
00202   }
00203   args.insert(args.end(), arg_end.get().begin(), arg_end.get().end());
00204 
00205   if (connect_mode == MODE_PLUGIN_LOAD)
00206     return connect_plugin(host, port, modules);
00207 
00208   // Open the right core library.
00209   if (arg_custom.filled())
00210     urbi_root.load_custom(arg_custom.value());
00211   else if (connect_mode == MODE_REMOTE)
00212     urbi_root.load_remote();
00213   else
00214     urbi_root.load_plugin();
00215 
00216   // If URBI_UOBJECT_PATH is not defined, first look in ., then in the
00217   // stdlib.
00218   std::string uobject_path = libport::xgetenv("URBI_UOBJECT_PATH", ".:");
00219 
00220   // Load the modules using our uobject library path.
00221   libport::xlt_advise dl;
00222   dl.ext().path().push_back(uobject_path, ":");
00223   foreach(const std::string& s, urbi_root.uobjects_path())
00224     dl.path().push_back(s);
00225   foreach (const std::string& s, modules)
00226     dl.open(s);
00227 
00228   return urbi_root.urbi_main(args, true, true);
00229 }
00230 
00231 extern "C"
00232 {
00233   int
00234   URBI_SDK_API
00235   urbi_launch(int argc, const char* argv[], UrbiRoot& root)
00236     try
00237     {
00238       return urbi_launch_(argc, argv, root);
00239     }
00240     catch (const std::exception& e)
00241     {
00242       std::cerr << argv[0] << ": " << e.what() << std::endl
00243                 << libport::exit(EX_FAIL);
00244     }
00245 }