//============================================================================= /** * @file nslist.cpp * * Naming Service listing utility * * @author Thomas Lockhart, NASA/JPL * @date 1999-06-03 * Enhanced 21 Jun, 2006 Simon Massey */ //============================================================================= #include "ace/SString.h" #include "orbsvcs/CosNamingC.h" #include "orbsvcs/Time_Utilities.h" #include "tao/Endpoint.h" #include "tao/Profile.h" #include "tao/Stub.h" #include "tao/ORB_Constants.h" #include "tao/AnyTypeCode/Any.h" #include "tao/Messaging/Messaging.h" #include "tao/Strategies/advanced_resource.h" #include "tao/PolicyC.h" #include "ace/Time_Value.h" #include "ace/Log_Msg.h" #include "ace/OS_NS_stdio.h" #include "ace/Argv_Type_Converter.h" #include "ace/OS_NS_ctype.h" //============================================================================ namespace { CORBA::ORB_var orb; bool showIOR = false, // Default decodes endpoints showCtxIOR = false, // Default no displaying naming context ior noLoops = false; // Default draw loopback arrows const char *myTree = "|", // Default string to draw tree "tram-lines" *myNode = "+"; // Default string to draw tree node end-points size_t sizeMyTree; // Initialised by main to strlen (myTree) size_t sizeMyNode; // Initialised by main to strlen (myNode) size_t maxDepth= 0; // Limit to display depth (default unlimited) ACE_Time_Value rtt = ACE_Time_Value::zero; // relative roundtrip timeout for ctx const CORBA::ULong MAX_COUNT_DEFAULT = 100; CORBA::ULong max_count = MAX_COUNT_DEFAULT; void list_context (const CosNaming::NamingContext_ptr, size_t level, CORBA::ULong max_count); CORBA::Object_ptr set_rtt(CORBA::Object_ptr obj); //========================================================================== class NestedNamingContexts { public: static void add (const CosNaming::NamingContext_ptr nc) { (void) new NestedNamingContexts( nc ); // This is not a leak (see constructor) } static void remove () { delete pBottom; } static size_t hasBeenSeen (const CosNaming::NamingContext_ptr nc) { size_t level = 1; for (const NestedNamingContexts *pMyNode= pBottom; pMyNode; ++level, pMyNode= pMyNode->pNext) { if (pMyNode->pnc->_is_equivalent (nc)) return level; // Loops backwards this number of levels } return 0; // Not seen before } private: static const NestedNamingContexts *pBottom; // Our current lowest level const CosNaming::NamingContext_ptr pnc; // This level's Naming Context const NestedNamingContexts *const pNext; // Next highest level NestedNamingContexts (const CosNaming::NamingContext_ptr nc) :pnc(nc), pNext(pBottom) // Adds the old list to this! { this->pBottom= this; // Doesn't leak this (it's the new start) } ~NestedNamingContexts () { this->pBottom= this->pNext; // this node removed from list. } // Outlaw copying NestedNamingContexts (const NestedNamingContexts &); NestedNamingContexts &operator= (const NestedNamingContexts &); }; const NestedNamingContexts *NestedNamingContexts::pBottom= 0; //========================================================================== void get_tag_name (CORBA::ULong tag, ACE_CString& tag_string) { if (tag == IOP::TAG_INTERNET_IOP) tag_string = "IIOP"; else if (tag == TAO_TAG_UIOP_PROFILE) tag_string = "UIOP"; else if (tag == TAO_TAG_SHMEM_PROFILE) tag_string = "SHMEM"; else if (tag == TAO_TAG_DIOP_PROFILE) tag_string = "DIOP"; else if (tag == TAO_TAG_COIOP_PROFILE) tag_string = "COIOP"; else if (tag == TAO_TAG_SCIOP_PROFILE) tag_string = "SCIOP"; else { char buffer[32]= {'\0'}; ACE_OS::sprintf( buffer, "%08x (%u)", tag, tag ); (tag_string = "Unknown tag: ") += buffer; } } //========================================================================== void display_endpoint_info (CORBA::Object_ptr obj, const size_t level) { TAO_Stub *stub = obj->_stubobj (); if (!stub) { ACE_DEBUG ((LM_DEBUG, " {Invalid Stub}\n")); return; } TAO_Profile* profile = stub->profile_in_use (); if (!profile) { ACE_DEBUG ((LM_DEBUG, " {Invalid Profile}\n")); return; } TAO_Endpoint* endpoint = profile->endpoint (); if (!endpoint) { ACE_DEBUG ((LM_DEBUG, " {Invalid Endpoint}\n")); return; } // Display protocol CORBA::ULong const tag = endpoint->tag (); ACE_CString tag_name; get_tag_name (tag, tag_name); ACE_DEBUG ((LM_DEBUG, "\n")); size_t count; for (count= 0; count < level; ++count) ACE_DEBUG ((LM_DEBUG, "%C ", myTree)); for (count= 0; count < sizeMyNode; ++count) ACE_DEBUG ((LM_DEBUG, " ")); ACE_DEBUG ((LM_DEBUG, " Protocol: %C\n", tag_name.c_str())); // Display Endpoint for (count= 0; count < level; ++count) ACE_DEBUG ((LM_DEBUG, "%C ", myTree)); for (count= 0; count < sizeMyNode; ++count) ACE_DEBUG ((LM_DEBUG, " ")); char buf[256]= {'\0'}; if (endpoint->addr_to_string (buf, sizeof(buf)-1u) < 0) ACE_OS::strcpy( buf, "{Endpoint too long}" ); ACE_DEBUG ((LM_DEBUG, " Endpoint: %C\n", buf)); } //========================================================================== // Display NS entries from a finite list. void show_chunk (const CosNaming::NamingContext_ptr nc, const CosNaming::BindingList &bl, size_t level) { for (CORBA::ULong i = 0; i < bl.length (); ++i) { size_t count; for (count= 0; count < level-1; ++count) ACE_DEBUG ((LM_DEBUG, "%C ", myTree)); ACE_DEBUG ((LM_DEBUG, "%C %C", myNode, bl[i].binding_name[0].id.in ())); if (bl[i].binding_name[0].kind[0]) ACE_DEBUG ((LM_DEBUG, " (Kind: %C)", bl[i].binding_name[0].kind.in ())); CosNaming::Name Name; Name.length (1); Name[0].id = CORBA::string_dup (bl[i].binding_name[0].id); Name[0].kind = CORBA::string_dup (bl[i].binding_name[0].kind); CORBA::Object_var obj = nc->resolve (Name); // If this is a context node, follow it down to the next level... if (bl[i].binding_type == CosNaming::ncontext) { ACE_DEBUG ((LM_DEBUG, ": Naming context")); obj = set_rtt(obj.in ()); CosNaming::NamingContext_var xc; try { xc = CosNaming::NamingContext::_narrow (obj.in ()); } catch (const CORBA::OBJECT_NOT_EXIST&) { xc= 0; ACE_DEBUG ((LM_DEBUG, " {Destroyed}")); } catch (const CORBA::TRANSIENT&) { xc= 0; ACE_DEBUG ((LM_DEBUG, " {Transient context IOR}")); } catch (const CORBA::TIMEOUT&) { xc= 0; ACE_DEBUG ((LM_DEBUG, " {Operation on conext IOR timed out}")); } if (const size_t backwards= NestedNamingContexts::hasBeenSeen (xc.in ())) { ACE_DEBUG ((LM_DEBUG, " (Binding Loop)\n")); if (!noLoops) { size_t count; for (count= 0; count < (level - backwards); ++count) ACE_DEBUG ((LM_DEBUG, "%C ", myTree)); ACE_DEBUG ((LM_DEBUG, "^")); size_t chars; while (++count < level) for (chars= 0; chars <= sizeMyTree; ++chars) ACE_DEBUG ((LM_DEBUG, "-")); for (chars= 0; chars < sizeMyNode; ++chars) ACE_DEBUG ((LM_DEBUG, "-")); ACE_DEBUG ((LM_DEBUG, "^\n")); } } else { if (showCtxIOR) { CORBA::String_var str = orb->object_to_string (obj.in ()); ACE_DEBUG ((LM_DEBUG, ": %C", str.in ())); } if (maxDepth != level) { ACE_DEBUG ((LM_DEBUG, "\n")); if (xc.in ()) { list_context (xc.in (), level + 1, max_count); } } else ACE_DEBUG ((LM_DEBUG, " {Max depth reached}\n")); } } // Mark this node as a reference else { ACE_DEBUG ((LM_DEBUG, ": Object Reference")); if (CORBA::is_nil (obj.in ())) ACE_DEBUG ((LM_DEBUG, " {Null}")); if (showIOR) { CORBA::String_var str = orb->object_to_string (obj.in ()); ACE_DEBUG ((LM_DEBUG, ": %C\n", str.in ())); } else if (CORBA::is_nil (obj.in ())) ACE_DEBUG ((LM_DEBUG, "\n")); else display_endpoint_info (obj.in(), level); } } } //========================================================================== void list_context (const CosNaming::NamingContext_ptr nc, size_t level, CORBA::ULong max_count) { CosNaming::BindingIterator_var it; CosNaming::BindingList_var bl; NestedNamingContexts::add (nc); nc->list (max_count, bl, it); show_chunk (nc, bl.in (), level); if (!CORBA::is_nil (it.in ())) { CORBA::Boolean more; do { more = it->next_n (max_count, bl); show_chunk (nc, bl.in (), level); } while (more); it->destroy (); } NestedNamingContexts::remove (); } //========================================================================== CORBA::Object_ptr set_rtt(CORBA::Object_ptr obj) { if (rtt != ACE_Time_Value::zero) { #if defined (TAO_HAS_CORBA_MESSAGING) && TAO_HAS_CORBA_MESSAGING != 0 TimeBase::TimeT roundTripTimeoutVal; ORBSVCS_Time::Time_Value_to_TimeT(roundTripTimeoutVal, rtt); CORBA::Any anyObjectVal; anyObjectVal <<= roundTripTimeoutVal; CORBA::PolicyList polList (1); polList.length (1); polList[0] = orb->create_policy(Messaging::RELATIVE_RT_TIMEOUT_POLICY_TYPE, anyObjectVal); CORBA::Object_var obj2 = obj->_set_policy_overrides(polList, CORBA::SET_OVERRIDE); polList[0]->destroy(); return obj2._retn(); #else ACE_DEBUG ((LM_DEBUG, "RTT not supported in TAO build.\n")); #endif } return CORBA::Object::_duplicate(obj); } } // end of local unnamed namespace //============================================================================ int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) { int err = 0; try { // Contact the orb orb = CORBA::ORB_init (argc, argv); // Scan through the command line options bool failed = false, showNSonly = false; ACE_TCHAR kindsep = ACE_TEXT('.'); ACE_TCHAR ctxsep[] = ACE_TEXT("/"); ACE_TCHAR *name = 0; const ACE_TCHAR *const pname = argv[0]; const ACE_TCHAR *nameService = 0; if (0 < argc) { while (0 < --argc) { ++argv; if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--ns"))) { if (!--argc) { ACE_DEBUG ((LM_DEBUG, "Error: --ns requires an argument\n")); failed = true; } else { ++argv; if (nameService) { ACE_DEBUG ((LM_DEBUG, "Error: more than one --ns.\n")); failed = true; } else if (showNSonly) { ACE_DEBUG ((LM_DEBUG, "Error: --nsior and --ns " "are both specified\n")); failed = true; } else nameService = *argv; } } else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--nsior"))) { if (showIOR || showCtxIOR || noLoops || nameService || name || maxDepth) { ACE_DEBUG ((LM_DEBUG, "Error: --nsior given " "with other options\n")); failed = true; } else showNSonly = true; } else if (0 == ACE_OS::strcmp(*argv, ACE_TEXT ("--ior"))) { if (showNSonly) { ACE_DEBUG ((LM_DEBUG, "Error: --nsior and --ior are " "both specified\n")); failed = true; } else showIOR = true; } else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--ctxior"))) { if (showNSonly) { ACE_DEBUG ((LM_DEBUG, "Error: --nsior and --ctxior are " "both specified\n")); failed = true; } else showCtxIOR = true; } else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--tree"))) { if (!--argc) { ACE_DEBUG ((LM_DEBUG, "Error: --tree requires an argument\n")); failed = true; } else { ++argv; if (showNSonly) { ACE_DEBUG ((LM_DEBUG, "Error: --nsior and --tree are " "both specified\n")); failed = true; } else myTree = ACE_TEXT_ALWAYS_CHAR (*argv); } } else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--node"))) { if (!--argc) { ACE_DEBUG ((LM_DEBUG, "Error: --node requires an argument\n")); failed = true; } else { ++argv; if (showNSonly) { ACE_DEBUG ((LM_DEBUG, "Error: --nsior and --node are " "both specified\n")); failed = true; } else myNode = ACE_TEXT_ALWAYS_CHAR (*argv); } } else if (0 == ACE_OS::strcmp(*argv, ACE_TEXT ("--noloops"))) { if (showNSonly) { ACE_DEBUG ((LM_DEBUG, "Error: --nsior and --noloops are " "both specified\n")); failed = true; } else noLoops = true; } else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--name"))) { if (name) { ACE_DEBUG ((LM_DEBUG, "Error: more than one --name\n")); failed = true; } else if (!--argc) { ACE_DEBUG ((LM_DEBUG, "Error: --name requires an argument\n")); failed = true; } else { ++argv; if (showNSonly) { ACE_DEBUG ((LM_DEBUG, "Error: --nsior and --name are " "both specified\n")); failed = true; } else name = *argv; } } else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--ctxsep"))) { if (!--argc) { ACE_DEBUG ((LM_DEBUG, "Error: --ctxsep requires a character\n")); failed = true; } else if (1 != ACE_OS::strlen(*(++argv))) { ACE_DEBUG ((LM_DEBUG, "Error: --ctxsep takes a single character (not %s)\n", *argv)); failed = true; } else if (showNSonly) { ACE_DEBUG ((LM_DEBUG, "Error: --nsior and --ctxsep are " "both specified\n")); failed = true; } else ctxsep[0] = (*argv)[0]; } else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--kindsep"))) { if (!--argc) { ACE_DEBUG ((LM_DEBUG, "Error: --kindsep requires a character\n")); failed = true; } else if (1 != ACE_OS::strlen(*(++argv))) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Error: --kindsep takes a single ") ACE_TEXT ("character (not %s)\n"), *argv)); failed = true; } else if (showNSonly) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Error: --nsior and --kindsep are ") ACE_TEXT ("both specified\n"))); failed = true; } else kindsep = (*argv)[0]; } else if (0 == ACE_OS::strcmp(*argv, ACE_TEXT ("--max"))) { if (maxDepth) { ACE_DEBUG ((LM_DEBUG, "Error: --max given more than once\n")); failed = true; } else if (!--argc || !ACE_OS::ace_isdigit (ACE_TEXT_ALWAYS_CHAR (*(++argv))[0])) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Error: --max requires a number\n"))); failed = true; } else if (showNSonly) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Error: --nsior and --max are ") ACE_TEXT ("both specified\n"))); failed = true; } else maxDepth= ACE_OS::atoi (*argv); } else if (0 == ACE_OS::strcmp(*argv, ACE_TEXT ("--rtt"))) { if (rtt != ACE_Time_Value::zero) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Error: --rtt given more than once\n"))); failed = true; } else if (!--argc || !ACE_OS::ace_isdigit (ACE_TEXT_ALWAYS_CHAR (*(++argv))[0])) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Error: --rtt requires a number\n"))); failed = true; } else rtt.set (ACE_OS::atoi (*argv), 0); } else if (0 == ACE_OS::strcmp(*argv, ACE_TEXT ("--count"))) { if (max_count != MAX_COUNT_DEFAULT) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Error: --count given more than once\n"))); failed = true; } else if (!--argc || !ACE_OS::ace_isdigit (ACE_TEXT_ALWAYS_CHAR (*(++argv))[0])) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Error: --count requires a number\n"))); failed = true; } else { CORBA::ULong count = ACE_OS::strtoul (ACE_TEXT_ALWAYS_CHAR (*argv), 0, 10); if (count > 0) { max_count = count; } else { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Error: --count requires a number") ACE_TEXT (" greater than 0\n"))); failed = true; } } } else { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Unknown option %s\n"), *argv)); failed = true; } } } if (failed) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n%s options:\n") ACE_TEXT (" --nsior {Display the naming service IOR and exit}\n") ACE_TEXT ("or:\n") ACE_TEXT (" --ns {Defaults to standard NameService}\n") ACE_TEXT (" --ior {Display ior for end points}\n") ACE_TEXT (" --ctxior {Display ior for naming contexts}\n") ACE_TEXT (" --tree \"xx\" {Defaults to | for drawing tramlines}\n") ACE_TEXT (" --node \"xx\" {Defaults to + for drawing nodes}\n") ACE_TEXT (" --noloops {Inhibit drawing of naming context loops}\n") ACE_TEXT (" --name {Lists sub-set, defaults to root}\n") ACE_TEXT (" --ctxsep { Context separation character, default /}\n") ACE_TEXT (" --kindsep { ID/Kind separation character, default .}\n") ACE_TEXT (" --max {If given, limits displayed sub-context depth}\n") ACE_TEXT (" --rtt {If given, sets the relative round trip timeout policy}\n") ACE_TEXT (" --count {If given, sets the maximum ") ACE_TEXT ("number of entries per request from the NameService}\n"), pname)); orb->destroy (); return 1; } // Initialise the lengths of the myTree and myNode draw strings. sizeMyTree= ACE_OS::strlen (myTree); sizeMyNode= ACE_OS::strlen (myNode); // Contact the name service CORBA::Object_var obj; if (nameService) obj = orb->string_to_object (nameService); else obj = orb->resolve_initial_references ("NameService"); obj = set_rtt(obj.in ()); CosNaming::NamingContext_var root_nc = CosNaming::NamingContext::_narrow (obj.in ()); if (CORBA::is_nil (root_nc.in ())) { ACE_DEBUG ((LM_DEBUG, "Error: nil root naming context\n")); orb->destroy (); return 1; } if (name) { // Assemble the name from the user string given CosNaming::Name the_name (0); ACE_TCHAR *cp; while (0 != (cp = ACE_OS::strtok (name, ctxsep))) { const int index= the_name.length(); the_name.length (index+1); ACE_TCHAR *kind = const_cast (ACE_OS::strchr (cp, kindsep)); if (kind) { *kind = '\0'; the_name[index].kind= CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR(++kind)); } the_name[index].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR(cp)); name = 0; // way strtok works } // Now find this sub-context and replace the root with it. obj = root_nc->resolve( the_name ); root_nc = CosNaming::NamingContext::_narrow (obj.in ()); if (CORBA::is_nil (root_nc.in ())) { ACE_DEBUG ((LM_DEBUG, "Error: Can't find naming context\n %s\n", name)); orb->destroy (); return 1; } } CORBA::String_var str = orb->object_to_string (root_nc.in ()); if (showNSonly) { ACE_DEBUG ((LM_DEBUG, "The NameService is located via:\n%C\n", str.in ())); } else { ACE_DEBUG ((LM_DEBUG, "Naming Service: %C\n---------------\n", ((showCtxIOR)? str.in () : ""))); list_context (root_nc.in (), 1, max_count); } } catch (const CORBA::Exception& ex) { ex._tao_print_exception ("Exception in nslist"); ++err; } try { orb->destroy (); } catch (const CORBA::Exception& ex) { ACE_DEBUG ((LM_DEBUG, "\nError:\n")); ex._tao_print_exception ("Exception in while shutting down"); ++err; } return err; }