/* * MIWCO --- Wireless CORBA support for MICO (OMG document formal/2004-04-02) * Home Location Agent main program * Copyright (C) 2001 Jaakko Kangasharju * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "HomeLocationAgent_impl.h" #ifdef HAVE_ANSI_CPLUSPLUS_HEADERS #include <fstream> #else #include <fstream.h> #endif #include <signal.h> #include <coss/CosNaming.h> #include <mico/impl.h> #include <mico/watm.h> using namespace std; // Useful helper functions namespace { bool finished; void sighandler (int sig) { finished = true; } } class HomeLocationService : public CORBA::ObjectAdapter { public: const char *get_oaid () const; CORBA::Boolean has_object (CORBA::Object_ptr); CORBA::Boolean is_local () const; #ifdef USE_CSL2 CORBA::Principal_ptr get_principal (CORBA::Object_ptr); #endif /* USE_CSL2 */ CORBA::Boolean invoke (CORBA::ORBMsgId, CORBA::Object_ptr, CORBA::ORBRequest *, CORBA::Principal_ptr, CORBA::Boolean); CORBA::Boolean bind (CORBA::ORBMsgId, const char *, const CORBA::ORB::ObjectTag &, CORBA::Address *); CORBA::Boolean locate (CORBA::ORBMsgId, CORBA::Object_ptr); CORBA::Object_ptr skeleton (CORBA::Object_ptr); void cancel (CORBA::ORBMsgId); void shutdown (CORBA::Boolean); void answer_invoke (CORBA::ORBMsgId, CORBA::Object_ptr, CORBA::ORBRequest *, CORBA::InvokeStatus); HomeLocationService (CORBA::ORB_ptr, HomeLocationAgent_impl *); ~HomeLocationService (); private: typedef HomeLocationAgent_impl::grid_data grid_data; CORBA::ORB_ptr _orb; HomeLocationAgent_impl *servant; grid_data::iterator find_terminal (CORBA::Object_ptr); }; HomeLocationService::HomeLocationService (CORBA::ORB_ptr orb, HomeLocationAgent_impl *hla) { _orb = orb; servant = hla; _orb->register_oa(this); } HomeLocationService::~HomeLocationService () { _orb->unregister_oa(this); } #define check(exp) if(!(exp)) return servant->grid_map.end() HomeLocationService::grid_data::iterator HomeLocationService::find_terminal (CORBA::Object_ptr o) { check(!CORBA::is_nil(o) && o->_ior()); CORBA::IORProfile *prof = o->_ior()->profile(CORBA::IORProfile::TAG_MOBILE_TERMINAL_IOP); if (prof != NULL) { WATM::WATMProfile *wprof = dynamic_cast<WATM::WATMProfile *>(prof); check(wprof != NULL); CORBA::Long tidlen; const CORBA::Octet *tidbuf = wprof->terminalid(tidlen); CORBA::OctetSeq tid(tidlen); tid.length(tidlen); memcpy(tid.get_buffer(), tidbuf, tidlen); return servant->grid_map.find(tid); } prof = o->_ior()->profile(); check(prof != NULL); CORBA::Long keylen; const CORBA::Octet *key = prof->objectkey(keylen); CORBA::Buffer buf(const_cast<CORBA::Octet *>(key)); #ifdef _WINDOWS MICO::CDRDecoder dc(&buf, FALSE, CORBA::DefaultEndian, 0, TRUE, 0, TRUE); #else MICO::CDRDecoder dc(&buf, FALSE); #endif CORBA::Octet bo; check(dc.get_octet(bo)); dc.byteorder(bo == 0 ? CORBA::BigEndian : CORBA::LittleEndian); char magic[4]; check(dc.get_chars_raw(magic, 4)); check(memcmp(magic, "MIOR", 4) == 0); check(dc.struct_begin()); { check(dc.struct_begin()); { CORBA::Octet major, minor; check(dc.get_octet(major)); check(dc.get_octet(minor)); } check(dc.struct_end()); CORBA::Octet blank; check(dc.get_octet(blank)); CORBA::ULong tidlen; check(dc.seq_begin(tidlen)); { CORBA::Octet *tidbuf = CORBA::OctetSeq::allocbuf(tidlen); check(dc.get_octets(tidbuf, tidlen)); CORBA::OctetSeq tid(tidlen, tidlen, tidbuf, TRUE); return servant->grid_map.find(tid); } } return servant->grid_map.end(); } const char * HomeLocationService::get_oaid () const { return "watm-terminal-locator"; } CORBA::Boolean HomeLocationService::has_object (CORBA::Object_ptr o) { return find_terminal(o) != servant->grid_map.end(); } CORBA::Boolean HomeLocationService::is_local () const { return TRUE; } #ifdef USE_CSL2 CORBA::Principal_ptr HomeLocationService::get_principal (CORBA::Object_ptr o) { assert(0); return (CORBA::Principal_ptr)0; } #endif /* USE_CSL2 */ CORBA::Boolean HomeLocationService::invoke (CORBA::ORBMsgId msgid, CORBA::Object_ptr o, CORBA::ORBRequest *req, CORBA::Principal_ptr pr, CORBA::Boolean response_exp) { /* * First make sure that GIOP 1.2 requests come with disposition * ReferenceAddr (Mobile Object Keys, even though MIWCO uses them, * are only for backwards compatibility). */ MICO::GIOPRequest *giop_req = dynamic_cast<MICO::GIOPRequest *>(req); if (giop_req == NULL) // We only handle GIOP requests return FALSE; if (giop_req->version() >= 0x0102 && o->_ior()->addressing_disposition() != GIOP::ReferenceAddr) { _orb->answer_invoke(msgid, CORBA::InvokeAddrDisp, o, req, GIOP::ReferenceAddr); return TRUE; } /* * Check that we really know the terminal and that it has an * associated Access Bridge. */ grid_data::iterator i = find_terminal(o); if (i == servant->grid_map.end() || CORBA::is_nil(i->second.current_wab)) { CORBA::OBJECT_NOT_EXIST ex; req->set_out_args(&ex); _orb->answer_invoke(msgid, CORBA::InvokeSysEx, CORBA::Object::_nil(), req, 0); return TRUE; } /* * Get all IIOP addresses for the Access Bridge. */ list<const MICO::InetAddress *> ab_addrs; const CORBA::Address *addr = NULL; while ((addr = i->second.current_wab->_ior()->addr(CORBA::IORProfile::TAG_INTERNET_IOP, FALSE, addr)) != NULL) { ab_addrs.push_back(dynamic_cast<const MICO::InetAddress *>(addr)); } if (ab_addrs.empty()) { // I wonder if this is the correct response CORBA::OBJECT_NOT_EXIST ex; req->set_out_args(&ex); _orb->answer_invoke(msgid, CORBA::InvokeSysEx, CORBA::Object::_nil(), req, 0); return TRUE; } /* * Replace addresses in the IIOP profiles of the received Mobile * IOR with addresses of the Access Bridge. KeyAddr needs to be * handled separately, since it only has a GIOPSimpleProf. */ CORBA::IORProfile *prof = NULL; const MICO::InetAddress *iaddr = NULL; if (o->_ior()->addressing_disposition() == GIOP::KeyAddr) { prof = o->_ior()->profile(); iaddr = ab_addrs.front(); CORBA::Long len; const CORBA::Octet *key = prof->objectkey(len); CORBA::IORProfile *iprof = iaddr->make_ior_profile(const_cast<CORBA::Octet *>(key), len, CORBA::MultiComponent(), 0x0102); o->_ior()->del_profile(prof); o->_ior()->add_profile(iprof); } else { while ((prof = o->_ior()->profile(CORBA::IORProfile::TAG_INTERNET_IOP, FALSE, prof)) != NULL) { MICO::IIOPProfile *iprof = dynamic_cast<MICO::IIOPProfile *>(prof); if (!ab_addrs.empty()) { iaddr = ab_addrs.front(); ab_addrs.pop_front(); } /* * iaddr is non-NULL at this point since ab_addrs is non-empty * when we enter the loop. */ iprof->addr(*iaddr); } } _orb->answer_invoke(msgid, CORBA::InvokeForward, o, req, 0); return TRUE; } CORBA::Boolean HomeLocationService::bind (CORBA::ORBMsgId msgid, const char *repoid, const CORBA::ORB::ObjectTag &oid, CORBA::Address *addr) { return FALSE; } CORBA::Boolean HomeLocationService::locate (CORBA::ORBMsgId msgid, CORBA::Object_ptr o) { /* * First make sure that GIOP 1.2 requests come with disposition * ReferenceAddr (Mobile Object Keys, even though MIWCO uses them, * are only for backwards compatibility). */ MICO::GIOPRequest *giop_req = dynamic_cast<MICO::GIOPRequest *>(o->_orbnc()->request(msgid)); if (giop_req == NULL) return FALSE; if (giop_req->version() >= 0x0102 && o->_ior()->addressing_disposition() != GIOP::ReferenceAddr) { _orb->answer_locate(msgid, CORBA::LocateAddrDisp, o, GIOP::ReferenceAddr); return TRUE; } /* * Check that we really know the terminal and that it has an * associated Access Bridge. */ grid_data::iterator i = find_terminal(o); if (i == servant->grid_map.end() || CORBA::is_nil(i->second.current_wab)) { _orb->answer_locate(msgid, CORBA::LocateUnknown, CORBA::Object::_nil(), 0); return TRUE; } /* * Get all IIOP addresses for the Access Bridge. */ list<const MICO::InetAddress *> ab_addrs; const CORBA::Address *addr = NULL; while ((addr = i->second.current_wab->_ior()->addr(CORBA::IORProfile::TAG_INTERNET_IOP, FALSE, addr)) != NULL) { ab_addrs.push_back(dynamic_cast<const MICO::InetAddress *>(addr)); } if (ab_addrs.empty()) { _orb->answer_locate(msgid, CORBA::LocateUnknown, CORBA::Object::_nil(), 0); return TRUE; } /* * Replace addresses in the IIOP profiles of the received Mobile * IOR with addresses of the Access Bridge. KeyAddr needs to be * handled separately, since it only has a GIOPSimpleProf. */ CORBA::IORProfile *prof = NULL; const MICO::InetAddress *iaddr = NULL; if (o->_ior()->addressing_disposition() == GIOP::KeyAddr) { prof = o->_ior()->profile(); iaddr = ab_addrs.front(); CORBA::Long len; const CORBA::Octet *key = prof->objectkey(len); CORBA::IORProfile *iprof = iaddr->make_ior_profile(const_cast<CORBA::Octet *>(key), len, CORBA::MultiComponent(), 0x0102); o->_ior()->del_profile(prof); o->_ior()->add_profile(iprof); } else { while ((prof = o->_ior()->profile(CORBA::IORProfile::TAG_INTERNET_IOP, FALSE, prof)) != NULL) { MICO::IIOPProfile *iprof = dynamic_cast<MICO::IIOPProfile *>(prof); if (!ab_addrs.empty()) { iaddr = ab_addrs.front(); ab_addrs.pop_front(); } /* * iaddr is non-NULL at this point since ab_addrs is non-empty * when we enter the loop. */ iprof->addr(*iaddr); } } _orb->answer_locate(msgid, CORBA::LocateForward, o, 0); return TRUE; } CORBA::Object_ptr HomeLocationService::skeleton (CORBA::Object_ptr o) { return CORBA::Object::_nil(); } void HomeLocationService::cancel (CORBA::ORBMsgId msgid) { } void HomeLocationService::shutdown (CORBA::Boolean wait_for_completion) { } void HomeLocationService::answer_invoke (CORBA::ORBMsgId msgid, CORBA::Object_ptr o, CORBA::ORBRequest *req, CORBA::InvokeStatus status) { assert(0); } int main (int argc, char *argv[]) { signal (SIGINT, sighandler); signal (SIGTERM, sighandler); CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); CORBA::Object_var obj = orb->resolve_initial_references("RootPOA"); PortableServer::POA_var root_poa = PortableServer::POA::_narrow(obj); PortableServer::POAManager_var root_mgr = root_poa->the_POAManager(); CORBA::PolicyList policies; policies.length(2); policies[0] = root_poa->create_lifespan_policy(PortableServer::PERSISTENT); policies[1] = root_poa->create_id_assignment_policy(PortableServer::USER_ID); PortableServer::POA_var hlr_poa = root_poa->create_POA("MobilitySupport", PortableServer::POAManager::_nil(), policies); PortableServer::POAManager_var hlr_mgr = hlr_poa->the_POAManager(); CosNaming::NamingContext_var inc; try { obj = orb->resolve_initial_references("NameService"); inc = CosNaming::NamingContext::_narrow(obj); } catch (const CORBA::Exception &) { inc = CosNaming::NamingContext::_nil(); } string rcfile = "~/.hlarc"; string prefix; MICOGetOpt::OptMap opts; opts["-WATMTerminalPrefix"] = "arg-expected"; opts["-WATMTerminalFile"] = "arg-expected"; MICOGetOpt opt_parser(opts); if (!opt_parser.parse(argc, argv, TRUE)) mico_throw(CORBA::INITIALIZE()); const MICOGetOpt::OptVec &o = opt_parser.opts(); for (MICOGetOpt::OptVec::const_iterator i = o.begin(); i != o.end(); ++i) { string arg = (*i).first; string val = (*i).second; if (arg == "-WATMTerminalPrefix") { prefix = val; } else if (arg == "-WATMTerminalFile") { rcfile = val; } } HomeLocationAgent_impl *servant = new HomeLocationAgent_impl(orb, hlr_poa, inc, prefix, rcfile); HomeLocationService *hls = new HomeLocationService(orb, servant); PortableServer::ObjectId_var oid = PortableServer::string_to_ObjectId("HomeLocationAgent"); hlr_poa->activate_object_with_id(oid, servant); MobileTerminal::HomeLocationAgent_var hlr = servant->_this(); if (!CORBA::is_nil(inc)) { CosNaming::Name hlr_name; hlr_name.length(1); hlr_name[0].id = CORBA::string_dup("MobilitySupport"); try { inc->bind_new_context(hlr_name); } catch (const CosNaming::NamingContext::AlreadyBound &) { } hlr_name.length(2); hlr_name[1].id = CORBA::string_dup("HomeLocationAgent"); inc->rebind(hlr_name, hlr); } ofstream of("home.ref"); of << orb->object_to_string(hlr) << endl; of.close(); root_mgr->activate(); hlr_mgr->activate(); finished = false; while (!finished) { orb->perform_work(); } hlr_poa->destroy(TRUE, TRUE); root_poa->destroy(TRUE, TRUE); delete hls; delete servant; return 0; }