AC_ARG_ENABLE(headless,
AS_HELP_STRING([--enable-headless],[Enable only packages for headless build]))
+AC_ARG_ENABLE(osgdebug,
+ AS_HELP_STRING([--enable-osgdebug],[Enable debug OSG libraries]))
+
AC_MSG_CHECKING([for headless mode])
AC_MSG_RESULT([$enable_headless])
CXXCPP="g++ -E"
AC_LANG_PUSH(C++)
+LIBS="$base_LIBS"
+
# OpenSceneGraph
case "${host}" in
*-apple-darwin*)
fi
fi
+osg_LIBS="$LIBS"
+AC_SUBST(osg_LIBS)
+LIBS="$base_LIBS"
+
AC_CHECK_HEADER(boost/version.hpp)
if test "x$ac_cv_header_boost_version_hpp" != "xyes"; then
echo
)
set(HLA_SOURCES
- RTIObjectClass.cxx
- RTIObjectInstance.cxx
- RTIFederate.cxx
HLAArrayDataElement.cxx
HLAArrayDataType.cxx
HLABasicDataElement.cxx
simgear_component(hla hla "${HLA_SOURCES}" "${HLA_HEADERS}")
if(RTI_FOUND)
- set(HLA13_HEADERS
- HLA13Federate.hxx
- )
- set(HLA13_SOURCES
+ set(RTI13_SOURCES
RTI13ObjectClass.cxx
RTI13ObjectInstance.cxx
RTI13Federate.cxx
- HLA13Federate.cxx
)
- simgear_component(hla13 hla "${HLA13_SOURCES}" "${HLA13_HEADERS}")
- set_property(TARGET sghla13 APPEND PROPERTY COMPILE_FLAGS "-I${RTI_INCLUDE_DIR}")
+ simgear_component(rti13 hla "${RTI13_SOURCES}" "")
+ set_property(TARGET sgrti13 APPEND PROPERTY COMPILE_FLAGS "-I${RTI_INCLUDE_DIR}")
endif()
+
+set(RTI_SOURCES
+ RTIObjectClass.cxx
+ RTIObjectInstance.cxx
+ RTIFederate.cxx
+ )
+simgear_component(rti hla "${RTI_SOURCES}" "")
+++ /dev/null
-// Copyright (C) 2009 - 2010 Mathias Froehlich - Mathias.Froehlich@web.de
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-
-#include "HLA13Federate.hxx"
-
-#include "RTI13Federate.hxx"
-
-namespace simgear {
-
-HLA13Federate::HLA13Federate() :
- HLAFederate(new RTI13Federate)
-{
-}
-
-HLA13Federate::~HLA13Federate()
-{
-}
-
-} // namespace simgear
+++ /dev/null
-// Copyright (C) 2009 - 2010 Mathias Froehlich - Mathias.Froehlich@web.de
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library 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
-// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-
-#ifndef HLA13Federate_hxx
-#define HLA13Federate_hxx
-
-#include "HLAFederate.hxx"
-
-namespace simgear {
-
-class HLA13Federate : public HLAFederate {
-public:
- HLA13Federate();
- virtual ~HLA13Federate();
-};
-
-} // namespace simgear
-
-#endif
SGVec2<T> _value;
};
+template<typename T>
+class HLAVec2Data {
+public:
+ HLAVec2Data() :
+ _value(new HLAVec2DataElement<T>(0))
+ { }
+ HLAVec2Data(const SGVec2<T>& value) :
+ _value(new HLAVec2DataElement<T>(0, value))
+ { }
+
+ operator const SGVec2<T>&() const
+ { return _value->getValue(); }
+ HLAVec2Data& operator=(const SGVec2<T>& value)
+ { _value->setValue(value); return *this; }
+
+ const SGVec2<T>& getValue() const
+ { return _value->getValue(); }
+ void setValue(const SGVec2<T>& value)
+ { _value->setValue(value); }
+
+ const HLAVec2DataElement<T>* getDataElement() const
+ { return _value.get(); }
+ HLAVec2DataElement<T>* getDataElement()
+ { return _value.get(); }
+
+ const HLAArrayDataType* getDataType() const
+ { return _value->getDataType(); }
+ void setDataType(const HLAArrayDataType* dataType)
+ { _value->setDataType(dataType); }
+
+private:
+ SGSharedPtr<HLAVec2DataElement<T> > _value;
+};
+
+typedef HLAVec2Data<float> HLAVec2fData;
+typedef HLAVec2Data<double> HLAVec2dData;
+
template<typename T>
class HLAVec3DataElement : public HLAAbstractArrayDataElement {
public:
SGVec3<T> _value;
};
+template<typename T>
+class HLAVec3Data {
+public:
+ HLAVec3Data() :
+ _value(new HLAVec3DataElement<T>(0))
+ { }
+ HLAVec3Data(const SGVec3<T>& value) :
+ _value(new HLAVec3DataElement<T>(0, value))
+ { }
+
+ operator const SGVec3<T>&() const
+ { return _value->getValue(); }
+ HLAVec3Data& operator=(const SGVec3<T>& value)
+ { _value->setValue(value); return *this; }
+
+ const SGVec3<T>& getValue() const
+ { return _value->getValue(); }
+ void setValue(const SGVec3<T>& value)
+ { _value->setValue(value); }
+
+ const HLAVec3DataElement<T>* getDataElement() const
+ { return _value.get(); }
+ HLAVec3DataElement<T>* getDataElement()
+ { return _value.get(); }
+
+ const HLAArrayDataType* getDataType() const
+ { return _value->getDataType(); }
+ void setDataType(const HLAArrayDataType* dataType)
+ { _value->setDataType(dataType); }
+
+private:
+ SGSharedPtr<HLAVec3DataElement<T> > _value;
+};
+
+typedef HLAVec3Data<float> HLAVec3fData;
+typedef HLAVec3Data<double> HLAVec3dData;
+
template<typename T>
class HLAVec4DataElement : public HLAAbstractArrayDataElement {
public:
SGVec4<T> _value;
};
+template<typename T>
+class HLAVec4Data {
+public:
+ HLAVec4Data() :
+ _value(new HLAVec4DataElement<T>(0))
+ { }
+ HLAVec4Data(const SGVec4<T>& value) :
+ _value(new HLAVec4DataElement<T>(0, value))
+ { }
+
+ operator const SGVec4<T>&() const
+ { return _value->getValue(); }
+ HLAVec4Data& operator=(const SGVec4<T>& value)
+ { _value->setValue(value); return *this; }
+
+ const SGVec4<T>& getValue() const
+ { return _value->getValue(); }
+ void setValue(const SGVec4<T>& value)
+ { _value->setValue(value); }
+
+ const HLAVec4DataElement<T>* getDataElement() const
+ { return _value.get(); }
+ HLAVec4DataElement<T>* getDataElement()
+ { return _value.get(); }
+
+ const HLAArrayDataType* getDataType() const
+ { return _value->getDataType(); }
+ void setDataType(const HLAArrayDataType* dataType)
+ { _value->setDataType(dataType); }
+
+private:
+ SGSharedPtr<HLAVec4DataElement<T> > _value;
+};
+
+typedef HLAVec4Data<float> HLAVec4fData;
+typedef HLAVec4Data<double> HLAVec4dData;
+
template<typename T>
class HLAQuatDataElement : public HLAAbstractArrayDataElement {
public:
#include "HLAFederate.hxx"
+#include "RTI13Federate.hxx"
#include "RTIFederate.hxx"
#include "RTIInteractionClass.hxx"
#include "RTIObjectClass.hxx"
namespace simgear {
-HLAFederate::HLAFederate(const SGSharedPtr<RTIFederate>& rtiFederate) :
- _rtiFederate(rtiFederate)
+HLAFederate::HLAFederate()
{
}
{
}
-const std::string&
+std::string
HLAFederate::getFederateType() const
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return std::string();
+ }
return _rtiFederate->getFederateType();
}
-const std::string&
+std::string
HLAFederate::getFederationName() const
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return std::string();
+ }
return _rtiFederate->getFederationName();
}
+bool
+HLAFederate::connect(Version version, const std::list<std::string>& stringList)
+{
+ if (_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Trying to connect to already connected federate!");
+ return false;
+ }
+ switch (version) {
+ case RTI13:
+ _rtiFederate = new RTI13Federate(stringList);
+ break;
+ case RTI1516:
+ SG_LOG(SG_IO, SG_ALERT, "HLA version RTI1516 not yet(!?) supported.");
+ // _rtiFederate = new RTI1516Federate(stringList);
+ break;
+ case RTI1516E:
+ SG_LOG(SG_IO, SG_ALERT, "HLA version RTI1516E not yet(!?) supported.");
+ // _rtiFederate = new RTI1516eFederate(stringList);
+ break;
+ default:
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Unknown rti version in connect!");
+ }
+ return _rtiFederate.valid();
+}
+
+bool
+HLAFederate::disconnect()
+{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
+ _rtiFederate = 0;
+ return true;
+}
+
bool
HLAFederate::createFederationExecution(const std::string& federation, const std::string& objectModel)
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->createFederationExecution(federation, objectModel);
}
bool
HLAFederate::destroyFederationExecution(const std::string& federation)
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->destroyFederationExecution(federation);
}
bool
HLAFederate::join(const std::string& federateType, const std::string& federation)
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->join(federateType, federation);
}
bool
HLAFederate::resign()
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->resign();
}
bool
HLAFederate::enableTimeConstrained()
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->enableTimeConstrained();
}
bool
HLAFederate::disableTimeConstrained()
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->disableTimeConstrained();
}
bool
HLAFederate::enableTimeRegulation(const SGTimeStamp& lookahead)
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->enableTimeRegulation(lookahead);
}
bool
HLAFederate::disableTimeRegulation()
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->disableTimeRegulation();
}
bool
HLAFederate::timeAdvanceRequestBy(const SGTimeStamp& dt)
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->timeAdvanceRequestBy(dt);
}
bool
HLAFederate::timeAdvanceRequest(const SGTimeStamp& dt)
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->timeAdvanceRequest(dt);
}
bool
HLAFederate::queryFederateTime(SGTimeStamp& timeStamp)
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->queryFederateTime(timeStamp);
}
+bool
+HLAFederate::modifyLookahead(const SGTimeStamp& timeStamp)
+{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
+ return _rtiFederate->modifyLookahead(timeStamp);
+}
+
bool
HLAFederate::queryLookahead(SGTimeStamp& timeStamp)
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->queryLookahead(timeStamp);
}
bool
HLAFederate::tick()
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->tick();
}
bool
HLAFederate::tick(const double& minimum, const double& maximum)
{
+ if (!_rtiFederate.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
+ return false;
+ }
return _rtiFederate->tick(minimum, maximum);
}
HLAFederate::ObjectModelFactory& objectModelFactory)
{
if (!_rtiFederate.valid()) {
- SG_LOG(SG_IO, SG_ALERT, "Could not process HLA XML object model file: "
- "No rti federate available!");
+ SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
return false;
}
class HLAFederate : public SGWeakReferenced {
public:
+ enum Version {
+ RTI13,
+ RTI1516,
+ RTI1516E
+ };
+
+ HLAFederate();
virtual ~HLAFederate();
+ /// connect to an rti
+ bool connect(Version version, const std::list<std::string>& stringList);
+ bool disconnect();
+
/// Get the name of the joined federate/federation
- const std::string& getFederateType() const;
- const std::string& getFederationName() const;
+ std::string getFederateType() const;
+ std::string getFederationName() const;
/// Create a federation execution
/// Semantically this methods should be static,
bool timeAdvanceRequest(const SGTimeStamp& dt);
bool queryFederateTime(SGTimeStamp& timeStamp);
+ bool modifyLookahead(const SGTimeStamp& timeStamp);
bool queryLookahead(SGTimeStamp& timeStamp);
/// Process messages
HLAInteractionClass* getInteractionClass(const std::string& name);
const HLAInteractionClass* getInteractionClass(const std::string& name) const;
-protected:
- HLAFederate(const SGSharedPtr<RTIFederate>& rtiFederate);
-
private:
SGSharedPtr<RTIFederate> _rtiFederate;
HLAVariantDataType.hxx
libsghla_a_SOURCES = \
- RTIObjectClass.cxx \
- RTIObjectInstance.cxx \
- RTIFederate.cxx \
HLAArrayDataElement.cxx \
HLAArrayDataType.cxx \
HLABasicDataElement.cxx \
if ENABLE_HLA13
-lib_LIBRARIES += libsghla13.a
-
-libsghla13_adir = @includedir@/hla
+lib_LIBRARIES += libsgrti13.a
-libsghla13_a_HEADERS = \
- HLA13Federate.hxx
+libsgrti13_adir = @includedir@/hla
-libsghla13_a_SOURCES = \
+libsgrti13_a_SOURCES = \
RTI13ObjectClass.cxx \
RTI13ObjectInstance.cxx \
- RTI13Federate.cxx \
- HLA13Federate.cxx
+ RTI13Federate.cxx
endif
+
+lib_LIBRARIES += libsgrti.a
+
+libsgrti_adir = @includedir@/hla
+
+libsgrti_a_SOURCES = \
+ RTIObjectClass.cxx \
+ RTIObjectInstance.cxx \
+ RTIFederate.cxx
+
_rtiAmbassador.queryFederateTime(fedTime);
timeStamp = toTimeStamp(fedTime);
}
+ void modifyLookahead(const SGTimeStamp& timeStamp)
+ { _rtiAmbassador.modifyLookahead(toFedTime(timeStamp)); }
void queryLookahead(SGTimeStamp& timeStamp)
{
RTIfedTime fedTime;
namespace simgear {
-RTI13Federate::RTI13Federate() :
+RTI13Federate::RTI13Federate(const std::list<std::string>& stringList) :
_tickTimeout(10),
_ambassador(new RTI13Ambassador)
{
+ if (stringList.empty()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "RTI: Ignoring non empty connect arguments while connecting to an RTI13 federation!");
+ }
}
RTI13Federate::~RTI13Federate()
return true;
}
+bool
+RTI13Federate::modifyLookahead(const SGTimeStamp& timeStamp)
+{
+ if (!_ambassador.valid()) {
+ SG_LOG(SG_NETWORK, SG_WARN, "RTI: Could not modify lookahead.");
+ return false;
+ }
+ try {
+ _ambassador->modifyLookahead(timeStamp);
+ } catch (RTI::InvalidLookahead& e) {
+ SG_LOG(SG_NETWORK, SG_WARN, "RTI: Could not modify lookahead: " << e._name << " " << e._reason);
+ return false;
+ } catch (RTI::FederateNotExecutionMember& e) {
+ SG_LOG(SG_NETWORK, SG_WARN, "RTI: Could not modify lookahead: " << e._name << " " << e._reason);
+ return false;
+ } catch (RTI::ConcurrentAccessAttempted& e) {
+ SG_LOG(SG_NETWORK, SG_WARN, "RTI: Could not modify lookahead: " << e._name << " " << e._reason);
+ return false;
+ } catch (RTI::SaveInProgress& e) {
+ SG_LOG(SG_NETWORK, SG_WARN, "RTI: Could not modify lookahead: " << e._name << " " << e._reason);
+ return false;
+ } catch (RTI::RestoreInProgress& e) {
+ SG_LOG(SG_NETWORK, SG_WARN, "RTI: Could not modify lookahead: " << e._name << " " << e._reason);
+ return false;
+ } catch (RTI::RTIinternalError& e) {
+ SG_LOG(SG_NETWORK, SG_WARN, "RTI: Could not modify lookahead: " << e._name << " " << e._reason);
+ return false;
+ }
+ return true;
+}
+
bool
RTI13Federate::queryLookahead(SGTimeStamp& timeStamp)
{
class RTI13Federate : public RTIFederate {
public:
- RTI13Federate();
+ RTI13Federate(const std::list<std::string>& stringList);
virtual ~RTI13Federate();
virtual bool createFederationExecution(const std::string& federation, const std::string& objectModel);
virtual bool timeAdvanceRequest(const SGTimeStamp& fedTime);
virtual bool queryFederateTime(SGTimeStamp& timeStamp);
+ virtual bool modifyLookahead(const SGTimeStamp& timeStamp);
virtual bool queryLookahead(SGTimeStamp& timeStamp);
/// Process messages
virtual bool timeAdvanceRequest(const SGTimeStamp& fedTime) = 0;
virtual bool queryFederateTime(SGTimeStamp& timeStamp) = 0;
+ virtual bool modifyLookahead(const SGTimeStamp& timeStamp) = 0;
virtual bool queryLookahead(SGTimeStamp& timeStamp) = 0;
/// Process messages
simgear_component(io io "${SOURCES}" "${HEADERS}")
add_executable(test_sock socktest.cxx)
-target_link_libraries(test_sock sgio sgstructure sgdebug)
+target_link_libraries(test_sock sgio sgstructure sgdebug ${OPENTHREADS_LIBRARY})
add_executable(test_http test_HTTP.cxx)
target_link_libraries(test_http
sgio sgstructure sgtiming sgmisc sgdebug
- ${RT_LIBRARY})
+ ${RT_LIBRARY}
+ ${OPENTHREADS_LIBRARY})
add_test(http ${EXECUTABLE_OUTPUT_PATH}/test_http)
add_executable(httpget httpget.cxx)
target_link_libraries(httpget
sgio sgstructure sgtiming sgmisc sgdebug
- ${RT_LIBRARY})
+ ${RT_LIBRARY}
+ ${OPENTHREADS_LIBRARY})
\ No newline at end of file
$(top_builddir)/simgear/misc/libsgmisc.a \
-lz \
$(network_LIBS) \
+ $(osg_LIBS) \
$(base_LIBS)
tcp_client_SOURCES = tcp_client.cxx
$(top_builddir)/simgear/misc/libsgmisc.a \
-lz \
$(network_LIBS) \
+ $(osg_LIBS) \
$(base_LIBS)
socktest_SOURCES = socktest.cxx
$(top_builddir)/simgear/misc/libsgmisc.a \
-lz \
$(network_LIBS) \
+ $(osg_LIBS) \
$(base_LIBS)
lowtest_SOURCES = lowtest.cxx
$(top_builddir)/simgear/debug/libsgdebug.a \
$(top_builddir)/simgear/bucket/libsgbucket.a \
$(top_builddir)/simgear/misc/libsgmisc.a \
- $(base_LIBS) -lz
+ $(base_LIBS) -lz $(osg_LIBS)
decode_binobj_SOURCES = decode_binobj.cxx
$(top_builddir)/simgear/debug/libsgdebug.a \
$(top_builddir)/simgear/bucket/libsgbucket.a \
$(top_builddir)/simgear/misc/libsgmisc.a \
- $(base_LIBS) -lz
+ $(base_LIBS) -lz $(osg_LIBS)
#define socklen_t int
#endif
+#include <map>
+
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/exception.hxx>
+#include <OpenThreads/Thread>
+#include <OpenThreads/Mutex>
+#include <OpenThreads/Condition>
+
+namespace {
+
+class Resolver : public OpenThreads::Thread
+{
+public:
+ static Resolver* instance()
+ {
+ if (!static_instance) {
+ OpenThreads::Thread::Init();
+
+ static_instance = new Resolver;
+ atexit(&Resolver::cleanup);
+ static_instance->start();
+ }
+
+ return static_instance;
+ }
+
+ static void cleanup()
+ {
+ static_instance->cancel();
+ }
+
+ Resolver()
+ {
+ // take the lock initially, thread will wait upon it once running
+ _lock.lock();
+ }
+
+ simgear::IPAddress* lookup(const string& host)
+ {
+ simgear::IPAddress* result = NULL;
+ _lock.lock();
+ AddressCache::iterator it = _cache.find(host);
+ if (it == _cache.end()) {
+ _cache[host] = NULL; // mark as needing looked up
+ _wait.signal(); // if the thread was sleeping, poke it
+ } else {
+ result = it->second;
+ }
+ _lock.unlock();
+ return result;
+ }
+
+ simgear::IPAddress* lookupSync(const string& host)
+ {
+ simgear::IPAddress* result = NULL;
+ _lock.lock();
+ AddressCache::iterator it = _cache.find(host);
+ if (it == _cache.end()) {
+ _lock.unlock();
+ result = new simgear::IPAddress;
+ bool ok = lookupHost(host.c_str(), *result);
+ _lock.lock();
+ if (ok) {
+ _cache[host] = result; // mark as needing looked up
+ } else {
+ delete result;
+ result = NULL;
+ }
+ } else { // found in cache, easy
+ result = it->second;
+ }
+ _lock.unlock();
+ return result;
+ }
+protected:
+ /**
+ * run method waits on a condition (_wait), and when awoken,
+ * finds any unresolved entries in _cache, resolves them, and goes
+ * back to sleep.
+ */
+ virtual void run()
+ {
+ while (true) {
+ _wait.wait(&_lock);
+ AddressCache::iterator it;
+
+ for (it = _cache.begin(); it != _cache.end(); ++it) {
+ if (it->second == NULL) {
+ string h = it->first;
+
+ _lock.unlock();
+ simgear::IPAddress* addr = new simgear::IPAddress;
+ // may take seconds or even minutes!
+ lookupHost(h.c_str(), *addr);
+ _lock.lock();
+
+ // cahce may have changed while we had the lock released -
+ // so iterators may be invalid: restart the traversal
+ it = _cache.begin();
+ _cache[h] = addr;
+ } // of found un-resolved entry
+ } // of un-resolved address iteration
+ } // of thread run loop
+ }
+private:
+ static Resolver* static_instance;
+
+ /**
+ * The actual synchronous, blocking host lookup function
+ * do *not* call this with any locks (mutexs) held, since depending
+ * on local system configuration / network availability, it
+ * may block for seconds or minutes.
+ */
+ bool lookupHost(const char* host, simgear::IPAddress& addr)
+ {
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_INET;
+ bool ok = false;
+
+ struct addrinfo* result0 = NULL;
+ int err = getaddrinfo(host, NULL, &hints, &result0);
+ if (err) {
+ SG_LOG(SG_IO, SG_WARN, "getaddrinfo failed for '" << host << "' : " << gai_strerror(err));
+ return false;
+ } else {
+ struct addrinfo* result;
+ for (result = result0; result != NULL; result = result->ai_next) {
+ if (result->ai_family != AF_INET) { // only accept IP4 for the moment
+ continue;
+ }
+
+ if (result->ai_addrlen != addr.getAddrLen()) {
+ SG_LOG(SG_IO, SG_ALERT, "mismatch in socket address sizes: got " <<
+ result->ai_addrlen << ", expected " << addr.getAddrLen());
+ continue;
+ }
+
+ memcpy(addr.getAddr(), result->ai_addr, result->ai_addrlen);
+ ok = true;
+ break;
+ } // of getaddrinfo results iteration
+ } // of getaddrinfo succeeded
+
+ freeaddrinfo(result0);
+ return ok;
+ }
+
+ OpenThreads::Mutex _lock;
+ OpenThreads::Condition _wait;
+
+ typedef std::map<string, simgear::IPAddress*> AddressCache;
+ AddressCache _cache;
+};
+
+Resolver* Resolver::static_instance = NULL;
+
+} // of anonymous namespace
+
namespace simgear
{
return;
}
- struct addrinfo hints;
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_family = AF_INET;
+// check the cache
+ IPAddress* cached = Resolver::instance()->lookupSync(host);
+ if (cached) {
+ memcpy(addr, cached->getAddr(), cached->getAddrLen());
+ }
- struct addrinfo* result0 = NULL;
- int err = getaddrinfo(host, NULL, &hints, &result0);
- if (err) {
- SG_LOG(SG_IO, SG_WARN, "getaddrinfo failed for '" << host << "' : " << gai_strerror(err));
- } else {
- struct addrinfo* result;
- for (result = result0; result != NULL; result = result->ai_next) {
- if (result->ai_family != AF_INET) { // only accept IP4 for the moment
- continue;
- }
-
- if (result->ai_addrlen != getAddrLen()) {
- SG_LOG(SG_IO, SG_ALERT, "mismatch in socket address sizes: got " <<
- result->ai_addrlen << ", expected " << getAddrLen());
- continue;
- }
-
- memcpy(addr, result->ai_addr, result->ai_addrlen);
- break;
- } // of getaddrinfo results iteration
- } // of getaddrinfo succeeded
-
- freeaddrinfo(result0);
addr->sin_port = htons (port); // fix up port after getaddrinfo
}
}
}
+bool IPAddress::lookupNonblocking(const char* host, IPAddress& addr)
+{
+ IPAddress* cached = Resolver::instance()->lookup(host);
+ if (!cached) {
+ return false;
+ }
+
+ addr = *cached;
+ return true;
+}
+
/* Create a string object representing an IP address.
This is always a string of the form 'dd.dd.dd.dd' (with variable
size numbers). */
return ntohs(addr->sin_port);
}
+void IPAddress::setPort(int port)
+{
+ addr->sin_port = htons(port);
+}
+
unsigned int IPAddress::getFamily () const
{
return addr->sin_family;
struct sockaddr* IPAddress::getAddr() const
{
+ if (addr == NULL) {
+ addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in));
+ memset(addr, 0, sizeof(struct sockaddr_in));
+ }
+
return (struct sockaddr*) addr;
}
*/
class IPAddress
{
- struct sockaddr_in* addr;
+ mutable struct sockaddr_in* addr;
public:
IPAddress () : addr(0) {}
IPAddress ( const char* host, int port ) ;
~IPAddress();
+ static bool lookupNonblocking(const char* host, IPAddress& addr);
+
IPAddress( const IPAddress& other );
const IPAddress& operator=(const IPAddress& other);
void set ( const char* host, int port ) ;
const char* getHost () const ;
unsigned int getPort() const ;
+ void setPort(int port);
+
unsigned int getIP () const ;
unsigned int getFamily () const ;
static const char* getLocalHost () ;
class Socket
{
int handle ;
-
+
public:
Socket () ;
#include <simgear/debug/logstream.hxx>
+
namespace simgear {
static NetChannel* channels = 0 ;
{
closed = true ;
connected = false ;
+ resolving_host = false;
accepting = false ;
write_blocked = false ;
should_delete = false ;
close () ;
Socket::setHandle ( handle ) ;
connected = is_connected ;
- //if ( connected ) this->handleConnect();
closed = false ;
}
}
int
-NetChannel::connect ( const char* host, int port )
+NetChannel::connect ( const char* h, int p )
{
- int result = Socket::connect ( host, port ) ;
- if (result == 0) {
- connected = true ;
- //this->handleConnect();
- return 0;
- } else if (isNonBlockingError ()) {
- return 0;
- } else {
- // some other error condition
- this->handleError (result);
- close();
- return -1;
- }
+ host = h;
+ port = p;
+ resolving_host = true;
+ return handleResolve();
}
int
if (accepting) {
if (!connected) {
connected = true ;
- //this->handleConnect();
}
this->handleAccept();
} else if (!connected) {
connected = true ;
- //this->handleConnect();
this->handleRead();
} else {
this->handleRead();
{
if (!connected) {
connected = true ;
- //this->handleConnect();
}
write_blocked = false ;
this->handleWrite();
}
+int
+NetChannel::handleResolve()
+{
+ IPAddress addr;
+ if (!IPAddress::lookupNonblocking(host.c_str(), addr)) {
+ return 0; // not looked up yet, wait longer
+ }
+
+ resolving_host = false;
+ addr.setPort(port);
+ int result = Socket::connect ( &addr ) ;
+ if (result == 0) {
+ connected = true ;
+ return 0;
+ } else if (isNonBlockingError ()) {
+ return 0;
+ } else {
+ // some other error condition
+ handleError (result);
+ close();
+ return -1;
+ }
+}
+
bool
NetChannel::poll (unsigned int timeout)
{
}
else if ( ! ch -> closed )
{
+ if (ch -> resolving_host )
+ {
+ ch -> handleResolve();
+ continue;
+ }
+
nopen++ ;
if (ch -> readable()) {
assert(nreads<MAX_SOCKETS);
#define SG_NET_CHANNEL_H
#include <simgear/io/raw_socket.hxx>
+#include <string>
namespace simgear
{
class NetChannel : public Socket
{
- bool closed, connected, accepting, write_blocked, should_delete ;
+ bool closed, connected, accepting, write_blocked, should_delete, resolving_host ;
NetChannel* next_channel ;
+ std::string host;
+ int port;
friend bool netPoll (unsigned int timeout);
void handleReadEvent (void);
void handleWriteEvent (void);
+ int handleResolve (void);
// These are meant to be overridden.
virtual void handleClose (void) {