Urbi SDK Remote for C++  2.7.5
main.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 
00012 
00013 #include <libport/cerrno>
00014 #include <libport/cstdio>
00015 #include <libport/debug.hh>
00016 #include <libport/unistd.h>
00017 
00018 #include <iostream>
00019 #include <list>
00020 #include <sstream>
00021 
00022 #include <libport/debug.hh>
00023 #include <libport/cli.hh>
00024 #include <libport/containers.hh>
00025 #include <libport/foreach.hh>
00026 #include <libport/lexical-cast.hh>
00027 #include <libport/package-info.hh>
00028 #include <libport/program-name.hh>
00029 #include <libport/sysexits.hh>
00030 
00031 #include <urbi/package-info.hh>
00032 #include <urbi/uexternal.hh>
00033 #include <urbi/umain.hh>
00034 #include <urbi/umessage.hh>
00035 #include <urbi/uobject.hh>
00036 #include <urbi/urbi-root.hh>
00037 #include <urbi/usyncclient.hh>
00038 #include <libuobject/remote-ucontext-impl.hh>
00039 using libport::program_name;
00040 
00041 GD_CATEGORY(Urbi.UrbiLaunch);
00042 
00043 namespace urbi
00044 {
00045   static impl::RemoteUContextImpl* defaultContext;
00046 
00047   static
00048   UCallbackAction
00049   debug(const UMessage& msg)
00050   {
00051     LIBPORT_USE(msg);
00052     GD_SWARN("unexpected message: " << msg);
00053     return URBI_CONTINUE;
00054   }
00055 
00056   static
00057   UCallbackAction
00058   endProgram(const UMessage& msg)
00059   {
00060     LIBPORT_USE(msg);
00061     GD_SWARN("got a disconnection message: " << msg);
00062     exit(0);
00063     return URBI_CONTINUE; //stupid gcc
00064   }
00065 
00066   static
00067   void
00068   usage()
00069   {
00070     std::cout <<
00071       "usage:\n" << libport::program_name() << " [OPTION]...\n"
00072       "\n"
00073       "Options:\n"
00074       "  -b, --buffer SIZE     input buffer size"
00075                  << " [" << UAbstractClient::URBI_BUFLEN << "]\n"
00076       "  -h, --help            output this message and exit successfully\n"
00077       "  -H, --host ADDR       server host name"
00078                  << " [" << UClient::default_host() << "]\n"
00079       "      --server          put remote in server mode\n"
00080       "      --no-sync-client  use UClient instead of USyncClient\n"
00081       "  -p, --port PORT       tcp port to listen to"
00082                  << " [" << UAbstractClient::URBI_PORT << "]\n"
00083       "  -r, --port-file FILE  file containing the port to listen to\n"
00084       "  -V, --version         print version information and exit\n"
00085       "  -d, --disconnect      exit program if disconnected [default]\n"
00086       "  -s, --stay-alive      do not exit program if disconnected\n"
00087       "  --describe            describe loaded UObjects and exit\n"
00088       "  --describe-file FILE  write the list of present UObjects to FILE\n"
00089                  << libport::exit (EX_OK);
00090   }
00091 
00092   static
00093   void
00094   version()
00095   {
00096     std::cout << urbi::package_info() << std::endl
00097               << libport::exit (EX_OK);
00098   }
00099 
00100   typedef std::vector<std::string> files_type;
00101   int
00102   initialize(const std::string& host, int port, size_t buflen,
00103              bool exitOnDisconnect, bool server, const files_type& files,
00104              bool useSyncClient)
00105   {
00106     GD_FINFO_TRACE("this is %s", program_name());
00107     GD_SINFO_TRACE(urbi::package_info());
00108     GD_FINFO_TRACE("remote component running on %s:%s", host, port);
00109     if (useSyncClient)
00110     {
00111       USyncClient::options o;
00112       o.server(server);
00113       new USyncClient(host, port, buflen, o);
00114     }
00115     else
00116     {
00117       GD_WARN("the no-sync-client mode is dangerous.  "
00118               "Any attempt to use synchronous operation will crash"
00119               " your program.");
00120       UClient::options o;
00121       o.server(server);
00122       setDefaultClient(new UClient(host, port, buflen, o));
00123     }
00124 
00125     if (!getDefaultClient() || getDefaultClient()->error())
00126       std::cerr << "ERROR: failed to connect, exiting..." << std::endl
00127                 << libport::exit(1);
00128 
00129     if (exitOnDisconnect)
00130       getDefaultClient()->setClientErrorCallback(callback(&endProgram));
00131 
00132 #ifdef LIBURBIDEBUG
00133     getDefaultClient()->setWildcardCallback(callback(&debug));
00134 #else
00135     getDefaultClient()->setErrorCallback(callback(&debug));
00136 #endif
00137 
00138     // Wait for client to be connected if in server mode.
00139     // Also wait for initialization exchanges.
00140     while (!getDefaultClient()
00141            || (!getDefaultClient()->isConnected()
00142                && !getDefaultClient()->error())
00143            || getDefaultClient()->connectionID().empty())
00144       usleep(20000);
00145 
00146     defaultContext = new impl::RemoteUContextImpl(
00147       (USyncClient*)dynamic_cast<UClient*>(getDefaultClient()));
00148 
00149     // Initialize in the correct thread.
00150     getDefaultClient()->notifyCallbacks
00151       (UMessage(*getDefaultClient(), 0, externalModuleTag,
00152                 libport::format("[%s]", UEM_INIT)));
00153     // Load initialization files.
00154     foreach (const std::string& file, files)
00155       getDefaultClient()->sendFile(file);
00156     return 0;
00157   }
00158 
00159   namespace
00160   {
00161     static
00162     void
00163     argument_with_option(const char* longopt,
00164                          char shortopt,
00165                          const std::string& val)
00166     {
00167       std::cerr
00168         << program_name()
00169         << ": warning: arguments without options are deprecated"
00170         << std::endl
00171         << "use `-" << shortopt << ' ' << val << '\''
00172         << " or `--" << longopt << ' ' << val << "' instead"
00173         << std::endl
00174         << "Try `" << program_name() << " --help' for more information."
00175         << std::endl;
00176     }
00177 
00178   }
00179 
00180 
00181   URBI_SDK_API int
00182   main(const libport::cli_args_type& args, UrbiRoot&, bool block, bool)
00183   {
00184     GD_INIT();
00185 
00186     std::string host = UClient::default_host();
00187     bool exitOnDisconnect = true;
00188     int port = UAbstractClient::URBI_PORT;
00189     bool server = false;
00190     bool useSyncClient = true;
00191     bool describeMode = false;
00192     std::string describeFile;
00193     size_t buflen = UAbstractClient::URBI_BUFLEN;
00194     // Files to load
00195     files_type files;
00196 
00197     // The number of the next (non-option) argument.
00198     unsigned argp = 1;
00199     for (unsigned i = 1; i < args.size(); ++i)
00200     {
00201       const std::string& arg = args[i];
00202       if (arg == "--buffer" || arg == "-b")
00203         buflen = libport::convert_argument<size_t>(args, i++);
00204       else if (arg == "--disconnect" || arg == "-d")
00205         exitOnDisconnect = true;
00206       else if (arg == "--file" || arg == "-f")
00207         files.push_back(libport::convert_argument<const char*>(args, i++));
00208       else if (arg == "--stay-alive" || arg == "-s")
00209         exitOnDisconnect = false;
00210       else if (arg == "--help" || arg == "-h")
00211         usage();
00212       else if (arg == "--host" || arg == "-H")
00213         host = libport::convert_argument<std::string>(args, i++);
00214       else if (arg == "--no-sync-client")
00215         useSyncClient = false;
00216       else if (arg == "--port" || arg == "-p")
00217         port = libport::convert_argument<unsigned>(args, i++);
00218       else if (arg == "--port-file" || arg == "-r")
00219         port =
00220           (libport::file_contents_get<int>
00221            (libport::convert_argument<const char*>(args, i++)));
00222       else if (arg == "--server")
00223         server = true;
00224       // FIXME: Remove -v some day.
00225       else if (arg == "--version" || arg == "-V" || arg == "-v")
00226         version();
00227       else if (arg == "--describe")
00228         describeMode = true;
00229       else if (arg == "--describe-file")
00230          describeFile = libport::convert_argument<const char*>(args, i++);
00231       else if (arg[0] == '-')
00232         libport::invalid_option(arg);
00233       else
00234         // A genuine argument.
00235         switch (argp++)
00236         {
00237           case 1:
00238             argument_with_option("host", 'H', args[i]);
00239             host = args[i];
00240             break;
00241           case 2:
00242             argument_with_option("port", 'p', args[i]);
00243             port = libport::convert_argument<unsigned>("port", args[i]);
00244             break;
00245           default:
00246             std::cerr << "unexpected argument: " << arg << std::endl
00247                       << libport::exit(EX_USAGE);
00248         }
00249     }
00250 
00251     if (describeMode)
00252     {
00253       foreach(baseURBIStarter* s, baseURBIStarter::list())
00254         std::cout << s->name << std::endl;
00255       foreach(baseURBIStarterHub* s, baseURBIStarterHub::list())
00256         std::cout << s->name << std::endl;
00257       return 0;
00258     }
00259     if (!describeFile.empty())
00260     {
00261       std::ofstream of(describeFile.c_str());
00262       foreach(baseURBIStarter* s, baseURBIStarter::list())
00263         of << s->name << std::endl;
00264       foreach(baseURBIStarterHub* s, baseURBIStarterHub::list())
00265         of << s->name << std::endl;
00266     }
00267     initialize(host, port, buflen, exitOnDisconnect, server, files,
00268                useSyncClient);
00269 
00270     if (block)
00271       while (true)
00272         usleep(30000000);
00273     return 0;
00274   }
00275 
00276 }